关于 security-audit
security-audit 是用于指导代码安全审查的技能,覆盖常见应用和基础设施风险,并提供检查项与示例命令。内容包括凭据、注入、访问控制、数据暴露、依赖项及特定技术栈的风险。
主要功能
- 01密钥与凭据扫描
- 02注入和输入验证检查
- 03身份验证与授权审查
- 04数据暴露与加密检查
- 05依赖项和 HTTP 标头检查
- 06特定框架的审查指南
适用场景
- 01检查代码库是否泄露凭据
- 02审查 API 代码中的注入与访问控制问题
- 03检查应用配置和依赖项
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ aakash-dhar/ claude-skills --skill security-audit安装后在 Claude Code 中输入/security-audit确认已加载。
详细介绍
安全审计技能
审计代码安全性时,请遵循以下结构化流程。认真对待每项发现——单个漏洞就可能危及整个系统。
1. 密钥与凭据
扫描整个代码库,查找暴露的密钥:
- 源代码中的硬编码 API 密钥、令牌、密码
- 提交到 Git 的配置文件中的密钥(.env、config.json、settings.py)
- 日志中的密钥——在 console.log、logger.info 等输出的敏感数据
- 错误消息中的密钥——泄露内部信息的堆栈跟踪或错误响应
- 注释中的密钥——遗留在 TODO 或已注释代码中的旧凭据
- Git 历史记录中的密钥——检查密钥是否曾被提交后又删除(仍保留在历史记录中)
检查命令:
# Search for common secret patterns
grep -rn "password\|secret\|api_key\|apikey\|token\|private_key\|AWS_SECRET\|DATABASE_URL" --include="*.ts" --include="*.js" --include="*.py" --include="*.env" --include="*.json" --include="*.yaml" --include="*.yml" .
# Check for .env files committed
git ls-files | grep -i "\.env"
# Check git history for secrets
git log --all --diff-filter=D -- "*.env" "*.pem" "*.key"
验证:
- 是否配置了
.gitignore,包含 .env、.pem、.key、*.p12? - 密钥是否通过环境变量或保险库加载(而非从文件加载)?
- 是否有
.env.example,其中使用的是占位值(而非真实密钥)?
2. 注入攻击
SQL 注入
// 🔴 VULNERABLE — string concatenation in query
const user = await db.query(`SELECT * FROM users WHERE id = '${req.params.id}'`);
// ✅ SAFE — parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
NoSQL 注入
// 🔴 VULNERABLE — user input directly in query object
const user = await User.find({ username: req.body.username });
// ✅ SAFE — explicitly cast to string
const user = await User.find({ username: String(req.body.username) });
命令注入
// 🔴 VULNERABLE — user input in shell command
exec(`convert ${req.body.filename} output.png`);
// ✅ SAFE — use execFile with arguments array
execFile('convert', [sanitizedFilename, 'output.png']);
XSS(跨站脚本攻击)
// 🔴 VULNERABLE — unsanitized HTML rendering
element.innerHTML = userInput;
// React: dangerouslySetInnerHTML={{ __html: userInput }}
// ✅ SAFE — use textContent or sanitize
element.textContent = userInput;
// React: use DOMPurify.sanitize() before dangerouslySetInnerHTML
路径遍历
// 🔴 VULNERABLE — user controls file path
const file = fs.readFileSync(`./uploads/${req.params.filename}`);
// ✅ SAFE — resolve and validate path stays within allowed directory
const safePath = path.resolve('./uploads', req.params.filename);
if (!safePath.startsWith(path.resolve('./uploads'))) throw new Error('Invalid path');
模板注入
- 检查是否将用户输入直接传递给模板引擎(Jinja2、EJS、Handlebars)
- 验证是否已启用自动转义
3. 身份验证与授权
身份验证缺陷
- 密码要求过弱——没有最小长度、复杂度要求或泄露检查
- 登录端点缺少速率限制(存在暴力破解风险)
- 多次登录失败后未锁定账户
- 密码存储不安全——明文、MD5、SHA1(使用适当成本参数的 bcrypt/argon2)
- 敏感操作缺少 MFA
- 会话令牌出现在 URL 中——令牌应放在请求头或 httpOnly Cookie 中
- 会话没有过期机制——令牌永不过期
授权缺陷
- 缺少授权检查——未验证用户权限即可访问端点
- IDOR(不安全的直接对象引用)——通过更改 ID 访问其他用户的数据
- 权限提升——普通用户可以访问管理员端点
- 缺少资源所有权检查——用户 A 可以修改用户 B 的数据
// 🔴 VULNERABLE — IDOR: no ownership check
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
res.json(order);
});
// ✅ SAFE — verify ownership
app.get('/api/orders/:id', async (req, res) => {
const order = await Order.findById(req.params.id);
if (order.userId !== req.user.id) return res.status(403).json({ error: 'Forbidden' });
res.json(order);
});
4. 数据泄露
- API 响应中的敏感数据——返回密码、令牌、SSN、完整信用卡号
- 生产环境中的详细错误消息——堆栈跟踪、数据库详细信息、内部路径
- 缺少字段筛选——返回整个数据库对象,而非指定字段
- 客户端存储中的敏感数据——令牌存放在 localStorage 中(应使用 httpOnly Cookie)
- 日志中的 PII——记录姓名、电子邮件、IP,且未进行脱敏
- 缺少数据加密——敏感数据以未加密形式静态存储
- CORS 配置错误——在需要身份验证的端点上使用
Access-Control-Allow-Origin: *
// 🔴 VULNERABLE — leaking sensitive fields
res.json(user);
// ✅ SAFE — explicit field selection
res.json({
id: user.id,
name: user.name,
email: user.email,
});
5. 输入验证
- 缺少验证——未检查请求正文、参数、查询字符串
- 类型混淆——预期为数字,却接受字符串
- 缺少长度限制——无界输入可能导致 DoS
- 缺少文件上传验证——未检查文件类型、大小或内容
- 正则表达式 DoS(ReDoS)——恶意输入导致灾难性回溯
- 缺少内容类型验证——接受意外的内容类型
验证:
- 是否使用了验证库(Zod、Joi、class-validator、Pydantic)?
- 是否所有 API 端点都在处理输入前进行验证?
- 文件上传是否按类型和大小进行限制,并经过恶意软件扫描?
6. 依赖项
运行以下检查:
# Node.js
npm audit
# or
npx better-npm-audit audit
# Python
pip audit
# or
safety check
# Check for outdated packages
npm outdated
pip list --outdated
检查以下内容:
- 依赖项中是否存在已知 CVE
- 是否存在带有已知漏洞的过时软件包
- 已弃用的软件包——两年或更久没有更新
- 拼写仿冒风险——确认软件包名称正确
- 权限过多——软件包请求了超出所需范围的访问权限
- 是否存在锁定文件——已提交 package-lock.json 或 yarn.lock
7. HTTP 安全标头
检查是否设置了以下标头:
Content-Security-Policy— 防止 XSS 和数据注入Strict-Transport-Security— 强制使用 HTTPSX-Content-Type-Options: nosniff— 防止 MIME 类型嗅探X-Frame-Options: DENY— 防止点击劫持Referrer-Policy— 控制引荐来源信息Permissions-Policy— 限制浏览器功能
# Check response headers
curl -I https://your-app.com
8. 密码学
- 弱哈希算法 — 使用 MD5 或 SHA1 存储密码(应使用 bcrypt、scrypt 或 argon2)
- 弱加密算法 — 使用 DES、RC4、ECB 模式(应使用 AES-256-GCM)
- 硬编码的加密密钥 — 密钥应存储在环境变量或密钥库中
- 缺少 TLS — 敏感数据通过 HTTP 连接传输
- 弱 JWT — 使用
alg: none,或使用短密钥的 HS256 - 可预测的随机值 — 使用 Math.random() 生成令牌(应使用 crypto.randomBytes)
// 🔴 VULNERABLE — predictable token
const token = Math.random().toString(36);
// ✅ SAFE — cryptographically secure
const token = crypto.randomBytes(32).toString('hex');
9. 基础设施与配置
- 在生产环境中启用调试模式 — 暴露详细错误、堆栈跟踪和调试端点
- 默认凭据 — admin/admin、root/root 等默认凭据仍可使用
- 开放了不必要的端口 — 数据库端口暴露在互联网上
- 缺少速率限制 — 无法防范 DoS
- 缺少请求大小限制 — 大型负载可能导致内存耗尽
- 不安全的 CORS 配置 — 已认证的端点允许通配符来源
- 缺少 CSRF 防护 — 更改状态的端点未使用 CSRF 令牌
10. 特定技术栈检查
Node.js / Express
- 确认已安装并配置 helmet 中间件
- 检查 express.json() 是否设置了大小限制:
express.json({ limit: '10kb' }) - 确认 Cookie 设置正确:httpOnly、secure、sameSite
- 检查合并对象时是否存在原型污染问题(lodash.merge、将用户输入传给 Object.assign)
- 确认 child_process 调用会清理所有输入
- 检查是否对身份验证端点应用了 express-rate-limit
- 检查事件发射器是否存在内存泄漏(缺少 removeListener)
- 确认没有将用户输入传给
eval()、Function()或vm.runInNewContext()
Python / Django
- 确认生产环境设置中
DEBUG = False - 检查
ALLOWED_HOSTS是否不是['*'] - 确认已启用 CSRF 中间件
- 检查是否存在未使用参数化查询的原始 SQL 查询
- 确认
SECRET_KEY从环境中读取,而非硬编码 - 检查是否对用户输入进行 pickle 反序列化(存在 RCE 风险)
- 确认 django-cors-headers 配置了特定来源
- 检查所有受保护的视图是否都使用了
@login_required或权限类 - 检查是否存在不安全的 YAML 加载(使用
yaml.load()时未设置Loader=SafeLoader) - 确认生产环境中
SECURE_SSL_REDIRECT、SESSION_COOKIE_SECURE、CSRF_COOKIE_SECURE均为 True
Python / Flask
- 确认
app.secret_key未被硬编码 - 检查受保护路由是否缺少
@login_required装饰器 - 确认已启用 Jinja2 自动转义(Flask 默认启用,但需检查自定义模板)
- 检查是否使用 flask-talisman 或类似工具设置安全标头
- 确认对身份验证端点和敏感端点应用了 flask-limiter
- 检查是否存在不安全的文件上传(缺少 werkzeug 的
secure_filename())
React / Next.js
- 检查是否将未经清理的输入传给
dangerouslySetInnerHTML - 确认没有将令牌存储在 localStorage 中(应使用 httpOnly Cookie)
- 检查客户端代码或代码包中是否包含敏感数据
- 确认环境变量仅对非敏感值使用
NEXT_PUBLIC_前缀 - 检查 URL 参数中是否存在开放重定向
- 确认 API 路由具有适当的身份验证中间件
- 检查 Server Actions 是否验证输入并检查授权
- 检查
getServerSideProps中是否有泄露到pageProps的敏感数据 - 确认
next.config.js已配置适当的安全标头 - 检查生产环境中是否暴露了源映射
Vue / Nuxt
- 检查
v-html是否使用了未经清理的用户输入 - 确认没有将令牌存储在 localStorage 中
- 检查
nuxt.config是否暴露了 runtime config 中的密钥 - 确认服务端中间件包含身份验证检查
- 检查是否通过
useAsyncData或useFetch将敏感数据从服务端泄露到客户端
Ruby on Rails
- 确认生产环境中设置了
config.force_ssl = true - 检查用户提供的内容是否使用了
html_safe或raw - 确认已启用
protect_from_forgery - 检查是否存在批量赋值漏洞(缺少
strong_parameters) - 确认
has_secure_password使用了 bcrypt - 检查是否使用用户输入调用不安全的
send()或constantize() - 确认
config.filter_parameters包含敏感字段
Go
- 检查查询中使用的
fmt.Sprintf是否存在 SQL 注入风险(应使用参数化查询) - 确认 TLS 配置使用的最低版本为 TLS 1.2
- 检查
http.ServeFile或os.Open是否存在路径遍历风险 - 确认错误处理得当(错误响应中不包含敏感数据)
- 检查共享状态是否存在竞态条件(缺少互斥锁)
- 确认安全敏感值使用
crypto/rand,而非math/rand - 检查是否存在可能导致 panic 的未检查类型断言
Java / Spring Boot
- 确认已配置 Spring Security,且敏感端点未使用
permitAll() - 检查
@Query注解中通过字符串拼接构造的查询是否存在 SQL 注入风险 - 确认已启用 CSRF 防护(Spring Security 默认启用)
- 检查是否存在反序列化漏洞(Jackson、Java 序列化)
- 确认请求体参数上存在
@Valid注解 - 检查
application.properties或application.yml中是否硬编码了凭据 - 确认 actuator 端点受到保护,且未向公众开放
- 检查依赖中是否存在 Log4j/Log4Shell 漏洞
PHP / Laravel
- 确认生产环境
.env中设置了APP_DEBUG=false - 检查原始 SQL 查询是否未使用参数绑定
- 确认 CSRF 中间件已应用于所有 POST/PUT/DELETE 路由
- 检查
eval()、exec()、system()是否使用了用户输入 - 确认文件上传使用了验证规则(MIME 类型、最大大小)
- 检查敏感路由是否受到
Auth::check()或中间件守卫的保护 - 确认通过
$fillable或$guarded防护批量赋值 - 检查是否使用
{!! !!}不安全地渲染用户输入的 Blade 内容
移动端(React Native / Flutter)
- 检查是否在 AsyncStorage/SharedPreferences 中存储了敏感数据(应使用加密存储)
- 确认 API 密钥未嵌入应用程序包中
- 检查敏感 API 调用是否启用了证书固定
- 确认深层链接处理程序在导航前会验证输入
- 检查应用日志中是否包含敏感数据(可通过 adb logcat / Console.app 查看)
- 确认生物识别身份验证已在服务端正确验证
- 检查 WebView 配置是否不安全(对不可信内容启用了 JavaScript)
支付安全
- 确认符合 PCI DSS 要求
- 检查是否从未存储或记录完整的信用卡号
- 确认支付处理使用了令牌化
- 检查 webhook 端点是否验证签名
- 确认退款端点具备适当的授权和速率限制
- 检查支付金额是否在服务端验证(而非信任客户端提供的金额)
- 确认支付确认页面不会在 URL 中暴露交易详情
- 检查支付处理中是否存在竞态条件(可能导致重复扣款)
AWS / 云基础设施
- 检查 IAM 策略是否权限过宽(
"Action": "*"、"Resource": "*") - 确认 S3 存储桶未公开访问
- 检查 RDS 实例或 EBS 卷是否未加密
- 确认安全组未允许从 0.0.0.0/0 访问敏感端口
- 检查是否硬编码了 AWS 凭据(应改用 IAM 角色)
- 确认已启用 CloudTrail 日志记录
- 检查是否存在运行敏感服务且可公开访问的 EC2 实例
- 确认密钥存储在 AWS Secrets Manager 或 Parameter Store 中
Docker / 容器
- 检查是否有以 root 身份运行的容器
- 确认基础镜像来自可信来源,并固定到特定版本
- 检查 Docker 镜像中是否包含密钥(使用构建密钥或运行时环境变量)
- 确认
.dockerignore排除了.env、.git、node_modules - 检查生产镜像中是否安装了不必要的软件包
- 确认已配置健康检查
- 检查是否暴露了不应公开的端口
输出格式
对于发现的每个漏洞:
[严重程度] 类别 — 文件:行号
- 漏洞:问题是什么
- 风险:攻击者可能利用此问题做什么
- 验证方法:如何利用该问题(供内部团队了解)
- 修复方法:解决问题所需的确切代码更改
- 参考资料:适用时提供 CWE 或 OWASP 链接
// vulnerable code
...
// fixed code
...
严重程度级别:
- 🔴 严重 — 可被主动利用。可能导致数据泄露、RCE 或系统完全失陷。立即修复。
- 🟠 高 — 需要一定努力即可利用。可能导致重大数据泄露或权限提升。下次部署前修复。
- 🟡 中 — 需要特定条件才能利用。在当前迭代中修复。
- 🟢 低 — 轻微问题或纵深防御改进。有空时修复。
总结
每次审计结束时都要包含:
- 风险评级 — 整体安全状况(严重 / 高 / 中 / 低风险)
- 严重问题数量 — 需要立即处理的问题数量
- 最危险的 3 个问题 — 按可利用性和影响程度排序
- 快速改进项 — 用时少于 30 分钟且能显著降低风险的修复
- 建议 — 长期改进措施(WAF、安全标头、在 CI 中扫描依赖项等)
- 做得好的方面 — 已落实且应继续保持的安全实践
评论
支持 Markdown