关于 security-review
security-review 是用于评估应用安全状况的审查流程,面向发布前检查、重大改动复核和安全审计准备。它结合代码库分析与浏览器测试,依据安全标准输出带证据的发现、修复建议和 YAML 回归测试。
主要功能
- 01攻击面与数据流梳理
- 02HTTP 安全头检查
- 03认证、会话与访问控制测试
- 04输入注入与客户端安全检查
- 05依赖及供应链审查
- 06报告、修复建议与 YAML 测试
适用场景
- 01发布前检查 Web 应用安全状况
- 02复核认证或授权改动
- 03为安全审计整理证据与发现
- 04安全事件后排查类似问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ shiplightai/ agent-skills --skill security-review安装后在 Claude Code 中输入/security-review确认已加载。
详细介绍
安全审查
依据行业标准评估应用的安全状况,并通过基于浏览器的渗透测试验证发现的问题。本次审查覆盖静态分析工具容易遗漏的攻击面,包括运行时行为、标头配置、身份验证流程和客户端漏洞。
使用时机
在以下情况下使用 /security-review:
- 发布新应用或新功能之前
- 添加身份验证或授权相关变更之后
- 处理敏感数据(用户凭据、支付信息、个人身份信息)时
- 准备安全审计时
- 发生安全事件后,检查是否存在类似问题
- 审查第三方集成时
参考标准
- OWASP Top 10 (2021) — Web 应用的主要安全风险
- OWASP ASVS v4.0 — 应用安全验证标准
- OWASP Session Management Cheat Sheet
- NIST 800-63B — 数字身份指南(身份验证)
- CWE/SANS Top 25 — 最危险的软件弱点
- Mozilla Observatory — HTTP 安全标头最佳实践
阶段概览
Phase 1: EDUCATE → Security context and what we check
Phase 2: SCOPE → Identify attack surface, auth mechanisms, data flows
Phase 3: ANALYZE → Automated checks + browser-based penetration testing
Phase 4: REPORT → Findings with evidence, CVE references, confidence scores
Phase 5: REMEDIATE → Fix guidance + YAML regression tests
阶段 1:说明
重要性: 数据泄露的平均成本为 445 万美元(IBM,2023 年)。83% 的 Web 应用至少存在一个严重漏洞。许多安全问题只有在运行时才能检测到,例如配置错误的标头、不安全的令牌存储和失效的访问控制,而这些正是基于浏览器的测试所能发现的问题。
本次审查通过基于浏览器的验证,依据客观安全标准检查你的应用。每项发现都引用了具体标准(OWASP、CWE、NIST)。
阶段 2:确定范围
收集背景信息
-
从代码库自动检测:
- 身份验证机制(JWT、会话、OAuth、API 密钥)
- 正在使用的框架安全功能(CSRF 令牌、CORS 配置、CSP)
- 存在已知漏洞的依赖项(
npm audit/pip audit) - API 路由和端点
- 环境变量处理方式
- 文件上传功能
- 第三方脚本和 CDN 的使用情况
-
逐项询问用户:
- 目标 URL:应用在哪里运行?
- 身份验证机制:用户如何登录?(自动检测后请用户确认)
- 测试凭据:你有可供我使用的测试账号吗?(身份验证测试所需)
- 敏感数据:应用会处理哪些敏感数据?(个人身份信息、支付信息、健康记录)
- 已知问题:你特别担心哪些方面?(可选)
-
梳理攻击面:
- 列出所有用户输入点(表单、URL 参数、文件上传、WebSocket 消息)
- 列出所有 API 端点及其身份验证要求
- 列出所有第三方集成
- 确认数据流:敏感数据从何处进入、如何处理和存储,以及从何处流出?
阶段 3:分析
使用 new_session 打开浏览器会话,并设置 record_evidence: true。运行所有适用类别的检查。
类别 A:HTTP 安全标头(HDR)
| 检查 ID | 检查项 | 标准 | 方法 |
|---|---|---|---|
| HDR-01 | 存在严格的 Content-Security-Policy 标头 | OWASP A05 | 检查响应标头 |
| HDR-02 | Strict-Transport-Security(HSTS)设置了较长的 max-age | OWASP Transport | 检查标头是否存在及其值 |
| HDR-03 | X-Content-Type-Options: nosniff | Mozilla Observatory | 检查标头 |
| HDR-04 | 设置了 X-Frame-Options 或 CSP frame-ancestors | OWASP Clickjacking | 检查标头 |
| HDR-05 | Referrer-Policy 设置恰当 | Privacy/Security | 检查标头值 |
| HDR-06 | Permissions-Policy 限制了敏感 API | Browser security | 检查摄像头、麦克风和地理位置策略 |
| HDR-07 | 不通过 Server/X-Powered-By 泄露版本信息 | Information leak | 检查标头中是否包含版本字符串 |
| HDR-08 | 为敏感页面设置 Cache-Control | OWASP Session | 检查已认证内容是否设置了 no-store |
| HDR-09 | CORS 限制不过于宽松 | OWASP A05 | 检查 Access-Control-Allow-Origin |
| HDR-10 | 不存在混合内容(HTTPS 页面加载 HTTP 资源) | Transport security | 检查所有资源 URL |
浏览器验证: 使用 act 通过 JavaScript 检查 document.querySelector('meta[http-equiv]'),并通过同源请求获取响应标头。使用 get_browser_console_logs 检查是否有混合内容警告。
类别 B:身份验证与会话管理(AUTH)
| 检查 ID | 检查项 | 标准 | 方法 |
|---|---|---|---|
| AUTH-01 | 不将令牌存储在 localStorage 中 | OWASP ASVS 3.3.2 | 检查 localStorage/sessionStorage 中是否有令牌 |
| AUTH-02 | 会话 Cookie 设置了 HttpOnly 标志 | OWASP Session | 检查 Set-Cookie 标头 |
| AUTH-03 | 会话 Cookie 设置了 Secure 标志 | OWASP Session | 检查 Set-Cookie 标头 |
| AUTH-04 | 会话 Cookie 设置了 SameSite 属性 | OWASP CSRF | 检查 Set-Cookie 标头 |
| AUTH-05 | 会话在空闲超时后过期 | OWASP ASVS 3.3.1 | 等待并验证会话是否失效 |
| AUTH-06 | 注销会使服务器端会话失效 | OWASP ASVS 3.3.1 | 注销后重放旧令牌,并检查响应 |
| AUTH-07 | 密码重置令牌只能使用一次 | OWASP Auth | 使用重置链接两次,验证第二次是否失败 |
| AUTH-08 | URL 参数中不包含凭据 | OWASP Transport | 检查 URL 中是否有令牌/密码 |
| AUTH-09 | 登录设有暴力破解防护 | OWASP Auth | 多次尝试登录失败,检查是否锁定/限速 |
| AUTH-10 | 状态更改请求设有 CSRF 防护 | OWASP A01 | 不带 CSRF 令牌提交表单 |
| AUTH-11 | 已验证 JWT 签名(如适用) | OWASP Auth | 发送修改后的 JWT,并检查是否被拒绝 |
| AUTH-12 | 使用 OAuth state 参数(如适用) | OWASP Auth | 检查 OAuth 流程是否包含 state 参数 |
浏览器验证: 使用 act 登录,通过 JavaScript 检查 Cookie(document.cookie——HttpOnly Cookie 不会显示,这是正确的)。检查 localStorage。执行注销并重放请求。尝试暴力破解(输入 5 次错误密码)。修改 JWT 令牌并进行测试。
类别 C:输入验证与注入(INJ)
| 检查 ID | 检查项 | 标准 | 方法 |
|---|---|---|---|
| INJ-01 | XSS:页面中的反射型输入 | OWASP A03 / CWE-79 | 在所有输入字段中提交 <script>alert(1)</script>,检查是否被渲染 |
| INJ-02 | XSS:数据库中的存储型输入 | OWASP A03 / CWE-79 | 通过表单提交脚本,检查后续页面加载时是否被渲染 |
| INJ-03 | 表单输入中的 SQL 注入 | OWASP A03 / CWE-89 | 提交 ' OR '1'='1 模式,检查是否出现错误 |
| INJ-04 | 通过 URL 参数进行开放重定向 | CWE-601 | 使用外部 URL 测试重定向参数 |
| INJ-05 | 文件操作中的路径遍历 | CWE-22 | 在与文件相关的参数中测试 ../../etc/passwd |
| INJ-06 | 输入字段中的命令注入 | CWE-78 | 在输入可能传递到 shell 的位置测试 ; ls 或 ` |
| INJ-07 | 用户内容中的 HTML 注入 | CWE-79 | 提交 HTML 标签,检查是否被渲染 |
| INJ-08 | URL scheme 验证(javascript:) | CWE-79 | 在 URL 输入字段中测试 javascript:alert(1) |
| INJ-09 | 文件上传验证 | OWASP A04 | 上传扩展名错误、体积过大或包含可执行内容的文件 |
| INJ-10 | API 输入验证 | OWASP A03 | 向 API 端点发送格式错误的 JSON、缺少字段或类型错误的数据 |
浏览器验证: 使用 act 在表单字段中填入测试载荷。提交后捕获页面状态。检查是否执行脚本、是否出现错误消息或异常行为。使用 get_browser_console_logs 查看可能表明存在注入向量的 JavaScript 错误。
重要提示: 这些是仅用于检测的非破坏性测试载荷。请勿尝试实际利用漏洞。基于 alert 的 XSS 测试使用 alert(1),没有危害。
类别 D:访问控制(AC)
| 检查 ID | 检查项 | 标准 | 方法 |
|---|---|---|---|
| AC-01 | 未通过身份验证时,受保护页面返回 401/403 | OWASP A01 | 未通过身份验证时访问受保护的 URL |
| AC-02 | 不存在 IDOR(不安全的直接对象引用) | OWASP A01 / CWE-639 | 更改 URL 中的资源 ID,检查是否可未经授权访问 |
| AC-03 | API 端点强制执行授权 | OWASP A01 | 使用错误或缺失的身份验证信息调用 API 端点 |
| AC-04 | 普通用户无法访问管理页面 | OWASP A01 | 使用普通用户会话访问管理路由 |
| AC-05 | 客户端源代码中不包含敏感数据 | 信息泄露 | 检查 JavaScript 包中是否包含 API 密钥和机密信息 |
| AC-06 | 禁用目录列表 | 信息泄露 | 访问目录 URL(例如 /api/、/static/) |
| AC-07 | 生产环境中未暴露调试端点 | OWASP A05 | 检查常见调试路径(/debug、/trace、/graphql playground) |
| AC-08 | 错误消息不会泄露内部详情 | OWASP A05 | 触发错误,检查是否出现堆栈跟踪或数据库详情 |
浏览器验证: 未通过身份验证时访问受保护页面。尝试访问属于其他用户的资源。使用 act 执行 JavaScript,扫描脚本内容,检查是否存在硬编码的机密信息。
类别 E:客户端安全(CLI)
| 检查 ID | 检查项 | 标准 | 方法 |
|---|---|---|---|
| CLI-01 | 客户端存储中不含敏感数据 | OWASP 存储 | 检查 localStorage、sessionStorage、IndexedDB |
| CLI-02 | CDN 资源启用子资源完整性(SRI) | 供应链 | 检查外部脚本/样式表上的 integrity 属性 |
| CLI-03 | 第三方脚本清单 | 供应链 | 列出所有外部脚本来源 |
| CLI-04 | 不使用 eval() 或 innerHTML 处理用户输入 | CWE-79 | 扫描 JavaScript 中的危险模式 |
| CLI-05 | 服务工作线程的作用域受到限制 | 客户端安全 | 检查 SW 注册作用域 |
| CLI-06 | WebSocket 连接使用 WSS | 传输 | 检查 WS 连接 URL |
| CLI-07 | 控制台日志中不含敏感数据 | 信息泄露 | 检查 get_browser_console_logs 的输出 |
| CLI-08 | 点击劫持防护有效 | OWASP 点击劫持 | 测试是否能在 iframe 中嵌入页面 |
浏览器验证: 使用 act 通过 JavaScript 枚举 localStorage 键,检查脚本标签的 SRI,并列出所有发往外部域名的网络请求。使用 get_browser_console_logs 检查是否有数据泄露。
类别 F:依赖项与供应链(DEP)
| 检查 ID | 检查项 | 标准 | 方法 |
|---|---|---|---|
| DEP-01 | 不存在已知存在漏洞的依赖项 | OWASP A06 / CWE-1035 | 运行 npm audit / pip audit |
| DEP-02 | 锁定文件存在且已提交 | 供应链 | 检查是否存在 package-lock.json / yarn.lock / pnpm-lock.yaml |
| DEP-03 | 不存在不必要的依赖项 | 攻击面 | 检查未使用的包 |
| DEP-04 | CDN 资源使用 SRI | 供应链 | 检查完整性属性(与 CLI-02 相同) |
| DEP-05 | 依赖项不存在仿冒包风险 | 供应链 | 将包名与已知包进行比对 |
验证: 运行依赖项审计命令。与第 2 阶段的代码库扫描结果交叉核对。
第 4 阶段:报告
生成结构化报告并保存到 shiplight/reports/security-review-{date}.md:
# Security Review Report
**Date:** {date}
**URL:** {url}
**Auth mechanism:** {type}
**Attack surface:** {summary}
## Overall Score: {X}/10 | Confidence: {X}%
## Score Breakdown
| Category | Score | Findings |
|----------|-------|----------|
| HTTP Headers (HDR) | 6/10 | 1 critical, 2 high |
| Auth & Sessions (AUTH) | 4/10 | 2 critical, 1 high |
| Input Validation (INJ) | 7/10 | 1 high, 2 medium |
| Access Control (AC) | 8/10 | 1 medium |
| Client-Side (CLI) | 5/10 | 1 critical, 1 high |
| Dependencies (DEP) | 9/10 | 1 low |
## Findings
### CRITICAL
#### AUTH-01: JWT stored in localStorage — XSS leads to full account takeover
- **Standard:** OWASP ASVS 3.3.2 / CWE-922
- **Finding:** Access token stored in `localStorage` under key `auth_token`, accessible to any XSS payload
- **Evidence:** [screenshot of Application > Storage showing JWT]
- **Attack scenario:** Any XSS vulnerability (even via third-party script) can exfiltrate all user tokens
- **CVSS estimate:** 8.1 (High)
- **Confidence:** 95%
...
置信度评分
- 90-100%:已在浏览器中利用并验证(例如,XSS 载荷已执行,已确认存在未授权访问)
- 70-89%:检查发现有力证据(例如,已确认缺少标头,观察到不安全的 Cookie 标志)
- 50-69%:有代码层面的证据,但未在运行时充分验证
- 低于 50%:不要报告——推测性太强
第 5 阶段:修复
对于每项发现,提供:
1. 修复指南
#### AUTH-01: JWT stored in localStorage
**Risk:** Any XSS → full account takeover
**File:** src/lib/auth.ts:47
**Current:** `localStorage.setItem('auth_token', jwt)`
**Fix:** Move to HttpOnly cookie set by the server
- Server: `Set-Cookie: token=<jwt>; HttpOnly; Secure; SameSite=Strict; Path=/`
- Client: Remove all localStorage token operations
- API calls: Cookies sent automatically (remove Authorization header)
**Migration steps:**
1. Add cookie-setting endpoint on server
2. Update API middleware to read from cookie
3. Remove client-side token storage
4. Update CORS to allow credentials
2. YAML 回归测试
- name: auth-01-no-tokens-in-localstorage
description: Verify authentication tokens are not stored in localStorage
severity: critical
standard: OWASP-ASVS-3.3.2
steps:
- URL: /login
- intent: Enter test username
action: fill
locator: "getByLabel('Email')"
value: "[email protected]"
- intent: Enter test password
action: fill
locator: "getByLabel('Password')"
value: "testpass123"
- intent: Click login button
action: click
locator: "getByRole('button', { name: 'Sign in' })"
- WAIT_UNTIL: User is logged in and dashboard is visible
timeout_seconds: 15
- description: Assert no auth tokens are stored in localStorage
js: |
const keys = Object.keys(localStorage);
const tokenKeys = keys.filter(k =>
/token|jwt|auth|session|access/i.test(k)
);
if (tokenKeys.length > 0) {
throw new Error(
`Auth tokens found in localStorage: ${tokenKeys.join(', ')}`
);
}
- VERIFY: No authentication tokens are stored in browser localStorage
将所有 YAML 测试保存到 shiplight/tests/security-review.test.yaml。
渗透测试深度级别
--quick:标头(HDR)+ Cookie 标志(AUTH-02/03/04)+ localStorage 检查(AUTH-01)+ 依赖项审计(DEP-01)。约 2 分钟。- 默认:所有类别,使用标准载荷。约 10 分钟。
--thorough:所有类别 + 扩展注入载荷 + IDOR 枚举 + 暴力破解测试 + 完整的第三方脚本分析。约 20-30 分钟。
提示
- 始终使用测试凭据,切勿使用生产凭据
- XSS 测试载荷不会造成破坏(
alert(1)),可安全用于预发布环境 - 进行已验证身份的测试时,登录后使用
save_storage_state保存会话 - 在基于浏览器的审查之前运行
npm audit,以便及早发现已知 CVE - 使用
get_browser_console_logs——许多安全问题都会产生控制台警告 - 使用
close_session关闭会话,并使用generate_html_report收集证据