mcpField
A
aif-security-checklist

aif-security-checklist

github.com/lee-to安全1.1k105 次安装今天更新
代码仓库

关于 aif-security-checklist

aif-security-checklist 是面向项目团队的安全审计技能,依据 OWASP Top 10 检查应用与基础设施风险。它支持按类别审计、跟踪忽略项,并输出机器可读的门禁结果。

主要功能

  1. 01基于 OWASP Top 10 的审计清单
  2. 02按安全类别进行专项检查
  3. 03自动化审计脚本
  4. 04在 SECURITY.md 跟踪忽略项
  5. 05附加机器可读的门禁结果

适用场景

  1. 01审查身份验证与会话处理
  2. 02检查代码中的注入和 XSS 风险
  3. 03评估 API 与基础设施安全
  4. 04记录待后续复核的接受风险

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lee-to/ai-factory --skill aif-security-checklist

安装后在 Claude Code 中输入/aif-security-checklist确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
AUTH-PATTERNS.md
PROMPT-INJECTION.md
RACE-CONDITIONS.md
scripts/
audit.sh

详细介绍

安全检查清单

基于 OWASP Top 10(2021)和行业最佳实践的全面安全检查清单。

快速参考

  • /aif-security-checklist — 完整审计检查清单
  • /aif-security-checklist auth — 身份验证和会话
  • /aif-security-checklist injection — SQL/NoSQL/命令注入
  • /aif-security-checklist xss — 跨站脚本攻击
  • /aif-security-checklist csrf — 跨站请求伪造
  • /aif-security-checklist secrets — 密钥和凭据
  • /aif-security-checklist api — API 安全
  • /aif-security-checklist infra — 基础设施安全
  • /aif-security-checklist prompt-injection — 大模型提示词注入
  • /aif-security-checklist race-condition — 竞态条件和 TOCTOU
  • /aif-security-checklist ignore <item> — 忽略特定检查项

配置

首先: 如果 .ai-factory/config.yaml 存在,请读取该文件以解析:

  • 路径: paths.security
  • 语言: language.ui 用于提示词、审计摘要和下一步指导;language.artifacts 用于被忽略项状态产物;language.technical_terms 用于被忽略项产物中面向用户的技术术语

如果 config.yaml 不存在,请使用默认值:

  • SECURITY.md:.ai-factory/SECURITY.md
  • ui_language:en
  • artifact_language:en
  • technical_terms_policy:keep

解析后的语言值:

  • ui_language = language.ui || "en"
  • artifact_language = language.artifacts || language.ui || "en"
  • technical_terms_policy = language.technical_terms || "keep"

如果 technical_terms_policy 不是 keep、translate 或 mixed 之一,则按 keep 处理。english 等旧值也按 keep 处理。

所有 AskUserQuestion 提示词、审计摘要、向用户显示的忽略项说明以及下一步指导都必须使用 ui_language 编写。

paths.security 指定的持久化 SECURITY.md 忽略项产物必须使用 artifact_language 编写。

模板和示例定义的是结构,而不是固定的英文输出。如果 artifact_language 不是 en,保存前请翻译面向用户的标题、表格标题、注释、生成的忽略项原因和审查指导。保留项目 ID、日期、作者用户名、命令、路径、配置键、包名称、API 名称、安全类别 ID、严重性/状态枚举值、原始错误,以及最终的 aif-gate-result JSON 架构,不做更改。对其他面向用户的术语应用 technical_terms_policy。

忽略项(SECURITY.md)

运行任何审计前,始终读取解析后的 SECURITY.md 路径(默认:.ai-factory/SECURITY.md)。如果文件存在,其中包含团队决定忽略的安全检查项。

忽略项的处理方式

当用户运行 /aif-security-checklist ignore <item> 时:

  1. 读取当前解析后的 SECURITY.md 文件(如果不存在则创建)
  2. 询问用户忽略此项的原因
  3. 按照下方格式将该项添加到文件中
  4. 确认已添加该项

运行任何审计(/aif-security-checklist 或特定类别)时:

  1. 在开始时读取解析后的 SECURITY.md 文件
  2. 对于与当前审计范围匹配的每个忽略项:
    • 不要将其标记为发现项
    • 而是在末尾的单独章节中显示:“⏭️ 忽略项”
    • 显示每个忽略项及其原因和日期,以便团队了解情况
  3. 未被忽略的项目照常审计
SECURITY.md 格式

保存前,请先以 artifact_language 呈现此结构。下方标题是规范结构标签,并非固定的英文输出;条目 ID 和表格字段含义保持不变。

# Security: Ignored Items

Items below are excluded from security-checklist audits.
Review periodically — ignored risks may become relevant.

| Item | Reason | Date | Author |
|------|--------|------|--------|
| no-csrf | SPA with token auth, no cookies used | 2025-03-15 | @dev |
| no-rate-limit | Internal microservice, behind API gateway | 2025-03-15 | @dev |

条目命名约定 — 使用简短的 kebab-case ID:

  • no-csrf — 未实现 CSRF 令牌
  • no-rate-limit — 未配置速率限制
  • no-https — 未强制使用 HTTPS
  • no-xss-csp — 缺少 CSP 标头
  • no-sql-injection — 未完全防止 SQL 注入
  • no-prompt-injection — 未缓解大模型提示词注入
  • no-race-condition — 缺少竞态条件防护
  • no-secret-rotation — 未轮换机密
  • no-auth-{route} — 特定路由缺少身份验证
  • verbose-errors — 暴露了详细错误信息
  • 或使用任何自定义描述性 ID
忽略条目的输出示例

显示审计结果时,请在末尾附上此部分:

⏭️ Ignored Items (from the resolved SECURITY.md artifact)
┌─────────────────┬──────────────────────────────────────┬────────────┐
│ Item            │ Reason                               │ Date       │
├─────────────────┼──────────────────────────────────────┼────────────┤
│ no-csrf         │ SPA with token auth, no cookies used │ 2025-03-15 │
│ no-rate-limit   │ Internal service, behind API gateway │ 2025-03-15 │
└─────────────────┴──────────────────────────────────────┴────────────┘
⚠️  2 items ignored. Run `/aif-security-checklist` without ignores to see full audit.

项目上下文

阅读 .ai-factory/skill-context/aif-security-checklist/SKILL.md — 若该文件存在,则为强制要求。

此文件包含 /aif-evolve 根据补丁、代码库约定和技术栈分析积累的项目专属规则。这些规则专为当前项目定制。

如何应用 skill-context 规则:

  • 将其视为对此技能通用指令的项目级覆盖规则
  • 当 skill-context 规则与本 SKILL.md 中的通用规则冲突时,以 skill-context 规则为准(更具体的上下文优先级更高——遵循与嵌套 CLAUDE.md 文件相同的原则)
  • 若没有冲突,则同时应用两者:SKILL.md 中的通用规则和 skill-context 中的项目规则
  • 即使 skill-context 规则看似与此技能的默认规则矛盾,也不得忽略——这些规则源自项目实践,证明默认规则并不足够
  • 重要: skill-context 规则适用于此技能的所有输出,包括安全检查清单、部署前检查清单和 SECURITY.md。如果 skill-context 规则要求“检查清单必须包含 X”或“审计必须涵盖 Y”,则必须相应补充检查清单。生成的安全报告若忽略 skill-context 规则,即为缺陷。

强制执行: 生成任何输出制品后,请根据所有 skill-context 规则进行核验。如果违反任何规则,必须先修正输出,再呈现给用户。


快速自动化审计

运行自动化安全审计脚本:

bash ~/{{skills_dir}}/security-checklist/scripts/audit.sh

此脚本会检查:

  • 代码中的硬编码机密
  • Git 中是否追踪了 .env
  • .gitignore 配置
  • npm audit(漏洞)
  • 生产代码中的 console.log
  • 安全任务标记

机器可读的门禁结果

对于 /aif-security-checklist 审计(完整审计或类别审计),请先输出供人阅读的安全报告,然后附上一个最终的 aif-gate-result fenced JSON 代码块。

除非该调用同时执行并报告审计结果,否则在 ignore <item> 写入流程中不要附加此门禁代码块。

状态映射:

  • fail:仍存在未忽略的严重/高危安全问题,或其他明确阻止生产部署的问题。
  • warn:仅存在中/低危问题、需要复审的已忽略条目、审计证据不完整,或审计命令受限。
  • pass:审计已完成,且不存在未忽略的问题。

机器可读字段:

  • 使用 "gate": "security"。
  • 使用 "status": "pass|warn|fail"。
  • 使用 "blocking": true|false。
  • "blockers": [ 中仅包含阻止生产部署的问题。
  • 在 "affected_files": [ 中包含受影响的路径。
  • 若适用工作流命令,则将 "suggested_next": { 设为 /aif-fix,否则设为 null。
  • JSON 代码块中不得包含机密、令牌、明文密码或私密凭据。
{
  "schema_version": 1,
  "gate": "security",
  "status": "warn",
  "blocking": false,
  "blockers": [],
  "affected_files": ["src/api/session.ts"],
  "suggested_next": {
    "command": "/aif-fix",
    "reason": "Address non-blocking security hardening findings."
  }
}

🔴 严重:部署前检查清单

上线前必须修复
  • 代码或 git 历史中不得包含机密信息
  • 验证并清理所有用户输入
  • 所有受保护的路由均启用身份验证
  • 强制使用 HTTPS(不使用 HTTP)
  • 防止 SQL/NoSQL 注入
  • 启用 XSS 防护
  • 对会改变状态的请求使用 CSRF 令牌
  • 启用速率限制
  • 错误消息不得泄露敏感信息
  • 在生产环境中禁用客户端调试日志,或通过明确的非生产环境检查进行保护
  • 生产环境 UI 绝不显示原始错误、堆栈跟踪、异常消息、SQL 错误、请求内部信息或上游服务详情
  • 扫描依赖项中的漏洞
  • 缓解 LLM 提示词注入(如使用 AI)
  • 防止关键操作(付款、库存)发生竞态条件

身份验证与会话

密码安全
✅ Requirements:
- [ ] Minimum 12 characters
- [ ] Hashed with bcrypt/argon2 (cost factor ≥ 12)
- [ ] Never stored in plain text
- [ ] Never logged
- [ ] Breach detection (HaveIBeenPwned API)

有关实现模式(argon2、bcrypt、PHP、Laravel)→ 请阅读 references/AUTH-PATTERNS.md

会话管理
✅ Checklist:
- [ ] Session ID regenerated after login
- [ ] Session timeout implemented (idle + absolute)
- [ ] Secure cookie flags set
- [ ] Session invalidation on logout
- [ ] Concurrent session limits (optional)

有关安全 Cookie 设置示例 → 请阅读 references/AUTH-PATTERNS.md

JWT 安全
✅ Checklist:
- [ ] Use RS256 or ES256 (not HS256 for distributed systems)
- [ ] Short expiration (15 min access, 7 day refresh)
- [ ] Validate all claims (iss, aud, exp, iat)
- [ ] Store refresh tokens securely (httpOnly cookie)
- [ ] Implement token revocation
- [ ] Never store sensitive data in payload

注入防护

SQL 注入
// ❌ VULNERABLE: String concatenation
const query = `SELECT * FROM users WHERE id = ${userId}`;

// ✅ SAFE: Parameterized query
const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);

// ✅ SAFE: ORM (Prisma/Eloquent/SQLAlchemy)
const user = await prisma.user.findUnique({ where: { id: userId } });
NoSQL 注入
// ❌ VULNERABLE: Direct user input — attack: { "$ne": "" }
const user = await db.users.findOne({ username: req.body.username });

// ✅ SAFE: Type validation
const username = z.string().parse(req.body.username);
命令注入
// ❌ VULNERABLE: exec(`convert ${userFilename} output.png`);
// ✅ SAFE: execFile('convert', [userFilename, 'output.png']);

跨站脚本攻击(XSS)

防护清单
- [ ] All user output HTML-encoded by default
- [ ] Content-Security-Policy header configured
- [ ] X-Content-Type-Options: nosniff
- [ ] Sanitize HTML if allowing rich text
- [ ] Validate URLs before rendering links
输出编码
// ❌ VULNERABLE: element.innerHTML = userInput; / dangerouslySetInnerHTML
// ✅ SAFE: element.textContent = userInput; / React: <div>{userInput}</div>
// ✅ If HTML needed: DOMPurify.sanitize(userInput)
// ❌ VULNERABLE: <?= $userInput ?> / {!! $userInput !!}
// ✅ SAFE: {{ $userInput }} (Blade) / htmlspecialchars($input, ENT_QUOTES, 'UTF-8')
内容安全策略

设置 CSP 标头:default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'


CSRF 防护

清单
- [ ] CSRF tokens on all state-changing requests
- [ ] SameSite=Strict or Lax on cookies
- [ ] Verify Origin/Referer headers
- [ ] Don't use GET for state changes
实现
  • 服务端渲染:使用 csurf 中间件,在隐藏表单字段和 AJAX 标头中嵌入令牌
  • 单页应用:使用双重提交 Cookie 模式——设置带有 sameSite: 'strict' 的可读 Cookie,客户端在标头中发送令牌,服务端进行比对

机密信息管理

绝对不要这样做
❌ Secrets in code
const API_KEY = "sk_live_abc123";

❌ Secrets in git
.env committed to repository

❌ Secrets in logs
console.log(`Connecting with password: ${password}`);

❌ Secrets in error messages
throw new Error(`DB connection failed: ${connectionString}`);
清单
- [ ] Secrets in environment variables or vault
- [ ] .env in .gitignore
- [ ] Different secrets per environment
- [ ] Secrets rotated regularly
- [ ] Access to secrets audited
- [ ] No secrets in client-side code
清理 Git 历史
# If secrets were committed, remove from history
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch path/to/secret-file" \
  --prune-empty --tag-name-filter cat -- --all

# Or use BFG Repo-Cleaner (faster)
bfg --delete-files .env
bfg --replace-text passwords.txt

# Force push (coordinate with team!)
git push origin --force --all

# Rotate ALL exposed secrets immediately!

API 安全

身份验证
- [ ] API keys not in URLs (use headers)
- [ ] Rate limiting per user/IP
- [ ] Request signing for sensitive operations
- [ ] OAuth 2.0 for third-party access
面向客户端的日志与错误
- [ ] Browser/client logs are disabled in production or routed through a logger that no-ops debug output in production
- [ ] `console.log`, `console.debug`, `console.info`, and verbose client telemetry are gated by explicit non-production checks
- [ ] Production UI shows only client-safe error messages with minimal operational detail
- [ ] Raw exceptions, stack traces, SQL/ORM errors, validation library internals, upstream responses, file paths, env names, and secrets never reach UI text
- [ ] Full error details are logged server-side only, correlated with a request/error ID returned to the client
- [ ] Client-safe error payloads use stable codes/messages such as `VALIDATION_FAILED`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `CONFLICT`, or `INTERNAL_ERROR`
const isProduction = process.env.NODE_ENV === 'production';

// ✅ Client debug output is explicit and removed/no-op in production paths
if (!isProduction) {
  console.debug('Form validation state', formState);
}

// ✅ Normalize unknown errors before rendering them in UI
function toClientError(error: unknown) {
  if (isKnownClientError(error)) {
    return { code: error.code, message: error.publicMessage };
  }

  return {
    code: 'INTERNAL_ERROR',
    message: 'Something went wrong. Try again later.',
  };
}
输入验证
// ✅ Validate all input with schema
import { z } from 'zod';

const CreateUserSchema = z.object({
  email: z.string().email().max(255),
  name: z.string().min(1).max(100),
  age: z.number().int().min(0).max(150).optional(),
});

app.post('/users', (req, res) => {
  const result = CreateUserSchema.safeParse(req.body);
  if (!result.success) {
    return res.status(400).json({
      error: {
        code: 'VALIDATION_FAILED',
        message: 'Some fields are invalid.',
        fields: result.error.issues.map((issue) => ({
          path: issue.path.join('.'),
          code: issue.code,
        })),
      },
    });
  }
  // result.data is typed and validated
});
响应安全
// ✅ Don't expose internal errors
app.use((err, req, res, next) => {
  console.error(err); // Log full error internally

  // Return generic message to client
  res.status(500).json({
    error: {
      code: 'INTERNAL_ERROR',
      message: 'Something went wrong. Try again later.',
    },
    requestId: req.id, // For support reference
  });
});

// ✅ Don't expose sensitive fields
const userResponse = {
  id: user.id,
  name: user.name,
  email: user.email,
  // ❌ Never: password, passwordHash, internalId, etc.
};

基础设施安全

标头清单
app.use(helmet()); // Sets many security headers

// Or manually:
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '0'); // Disabled, use CSP instead
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');
依赖项安全
# Check for vulnerabilities
npm audit
pip-audit
cargo audit

# Auto-fix where possible
npm audit fix

# Keep dependencies updated
npx npm-check-updates -u
部署清单
- [ ] HTTPS only (redirect HTTP)
- [ ] TLS 1.2+ only
- [ ] Security headers configured
- [ ] Debug mode disabled
- [ ] Default credentials changed
- [ ] Unnecessary ports closed
- [ ] File permissions restricted
- [ ] Logging enabled (but no secrets)
- [ ] Backups encrypted
- [ ] WAF/DDoS protection (for public APIs)

竞态条件

有关竞态条件的详细模式(重复扣款、TOCTOU、乐观锁、幂等键、分布式锁)→ 请阅读 references/RACE-CONDITIONS.md

防护清单
- [ ] Financial operations use database transactions with proper isolation
- [ ] Inventory/stock checks use atomic decrement (not read-then-write)
- [ ] Idempotency keys on payment and mutation endpoints
- [ ] Optimistic locking (version column) on concurrent updates
- [ ] File operations use exclusive locks where needed
- [ ] No TOCTOU gaps between permission check and action
- [ ] Rate limiting to reduce exploitation window

提示词注入(LLM 安全)

有关提示词注入的详细模式(直接注入、间接注入、工具安全、输出验证、RAG)→ 请阅读 references/PROMPT-INJECTION.md

防护清单
- [ ] User input never concatenated directly into system prompts
- [ ] Input/output boundaries clearly separated (delimiters, roles)
- [ ] LLM output treated as untrusted (never executed as code/commands)
- [ ] Tool calls from LLM validated and sandboxed
- [ ] Sensitive data excluded from LLM context
- [ ] Rate limiting on LLM endpoints
- [ ] Output filtered for PII/secrets leakage
- [ ] Logging & monitoring for anomalous prompts

快速审计命令

# Find hardcoded secrets
grep -rn "password\|secret\|api_key\|token" --include="*.ts" --include="*.js" .

# Check for vulnerable dependencies
npm audit --audit-level=high

# Find unfinished security markers
grep -rn "[T][O][D][O].*security\|[F][I][X][M][E].*security\|[X][X][X].*security" .

# Check for console.log in production code
grep -rn "console\.log" src/

# Check for verbose browser logs that need a non-production guard
grep -rn "console\.\(log\|debug\|info\|trace\)" --include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" src/

# Check for raw error rendering patterns in UI/client code
grep -rn "\(error\.message\|err\.message\|String(error)\|String(err)\|stack\)" --include="*.tsx" --include="*.jsx" --include="*.ts" --include="*.js" src/

# Find prompt injection risks (unsanitized input in LLM calls)
grep -rn "system.*\${.*}" --include="*.ts" --include="*.js" .
grep -rn "innerHTML.*llm\|innerHTML.*response\|innerHTML.*completion" --include="*.ts" --include="*.js" .

严重程度参考

问题严重程度修复时限
SQL 注入🔴 严重立即
身份验证绕过🔴 严重立即
机密信息泄露🔴 严重立即
XSS(存储型)🔴 严重< 24 小时
提示词注入(直接)🔴 严重立即
竞态条件(财务)🔴 严重立即
提示词注入(间接)🟠 高< 1 周
竞态条件(数据)🟠 高< 1 周
CSRF🟠 高< 1 周
XSS(反射型)🟠 高< 1 周
缺少速率限制🟡 中< 2 周
错误信息过于详细🟡 中< 2 周
缺少标头🟢 低< 1 个月

提示: 安全审计后上下文内容较多。继续处理其他任务前,可考虑使用 /clear 或 /compact。

制品归属与配置策略

  • 主要归属:通过 ignore 流程创建的忽略项状态,由解析后的 SECURITY.md 制品(默认:.ai-factory/SECURITY.md)负责。
  • 写入策略:审计发现通常以对话形式输出;除非用户明确要求,否则持久化写入仅限于上述忽略状态制品。
  • 配置策略:支持配置感知。忽略状态制品使用 paths.security,提示词和审计摘要使用 language.ui,忽略项制品使用 language.artifacts,人类可读术语策略使用 language.technical_terms;审计范围则根据仓库证据和审计命令确定。

评论

支持 Markdown