mcpField
R
reviewing-cryptography

reviewing-cryptography

github.com/trilwu安全17753 次安装12 周前更新
代码仓库

关于 reviewing-cryptography

用于代码审查的密码学技能,聚焦加密、认证、密钥、令牌、密码、随机数和 TLS 的误用。它提供具体检查步骤,并要求审查结论说明可导致的攻击及明确修正方案。

主要功能

  1. 01认证加密与随机数检查
  2. 02密钥管理和轮换审查
  3. 03密码哈希与随机性检查
  4. 04恒定时间比较审查
  5. 05JWT、签名和 TLS 验证
  6. 06协议层误用检查清单

适用场景

  1. 01审查加解密代码
  2. 02检查令牌和 API 签名方案
  3. 03评估 TLS 与证书验证
  4. 04检查密码和秘密存储

安装

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

$npx skills add https://github.com/trilwu/secskills --skill reviewing-cryptography

安装后在 Claude Code 中输入/reviewing-cryptography确认已加载。

详细介绍

审查密码学

几乎没有真正的系统是被密码分析攻破的。它们通常是因误用而遭到破坏: 重复使用 nonce、未认证的密文、会提前返回的比较操作、提交到 git 的密钥。 审查误用问题,并将原语设计留给密码学家。

适用场景

  • 审计执行加密、解密、签名、验证或哈希的代码
  • 审查密钥管理、轮换和存储
  • 评估 TLS/mTLS 配置和证书验证
  • 审查 JWT、会话令牌和 API 签名方案
  • 检查密码和秘密的存储方式
  • 评估安全相关值的随机性质量

不适用场景

  • 设计新的原语或协议 — 这需要密码学家进行正式审查,而非代码审计
  • 在 CTF 中破解密码学 — 这是不同的专业领域;请使用面向 solving 的进攻型技能和已知攻击工具
  • 常规代码审查 — 请使用 auditing-code-for-vulnerabilities
  • 密码破解 — 请使用 cracking-passwords

误用检查清单

按顺序逐项检查。每一项都曾发现过真实的生产环境故障。

1. 密文是否经过认证?

未进行认证的加密是最常见的严重问题。如果 CBC 或 CTR 没有 MAC,攻击者就能修改明文;如果还存在解密预言机,则能恢复明文(填充预言机)。

Good:  AES-GCM, ChaCha20-Poly1305, AES-CBC + HMAC (encrypt-then-MAC)
Bad:   AES-CBC alone, AES-ECB (ever), CTR without a MAC, MAC-then-encrypt
rg -n 'AES/ECB|AES\.MODE_ECB|CipherMode\.ECB|"AES"\)' -i
rg -n 'AES/CBC/PKCS5Padding|MODE_CBC|createCipheriv\(.*cbc' -i

如果看到 CBC,就查找 MAC。如果没有 MAC,无论密文如何传输,这都属于问题。

2. Nonce 和 IV 的处理
模式规则后果
GCM / ChaCha20-Poly1305绝不重复使用同一对(密钥,nonce)灾难性后果:泄露认证密钥,伪造变得轻而易举
CBC每条消息的 IV 必须不可预测且随机选择明文攻击(BEAST 类)
CTR同一密钥下绝不重复使用计数器密钥流重复使用;明文异或结果
# The classic bug: a fixed or zero IV
rg -n 'iv\s*=\s*(b?["\x27]0|new byte\[\d+\]|bytes\(\d+\)|\[0\]\s*\*)' -i
rg -n 'IvParameterSpec\(new byte\[16\]\)|createCipheriv\([^,]+,[^,]+,\s*["\x27]'

GCM 使用随机 96 位 nonce 时,每个密钥处理约 2^32 条消息以内是安全的。 基于计数器的 nonce 更安全,但前提是计数器状态确实能在重启后保留,且不会在多个实例间重复。询问计数器存储在哪里;如果答案是“在内存中”,再加上水平扩展,就意味着会重复使用。

3. 密钥管理
  • 密钥从哪里来?硬编码、环境变量、KMS/HSM,还是派生而来?
  • 检查所有这些位置:硬编码的密钥、源码中的密钥、提交到仓库的配置文件中的密钥、容器镜像中的密钥、CI 日志中的密钥。
  • 密钥是否只用于单一用途?在加密和签名之间,或不同租户之间重复使用密钥,都是问题。
  • 是否存在密钥轮换途径?无法轮换的系统,在密钥泄露时便无从应对。
  • 派生密钥:是否使用了合适的 KDF(密钥材料使用 HKDF,密码使用 Argon2id/scrypt/PBKDF2)?对密码直接计算 SHA-256 并不属于 KDF。
rg -n 'BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY|-----BEGIN'
rg -n '(secret|api[_-]?key|password|token)\s*[:=]\s*["\x27][A-Za-z0-9/+=]{16,}' -i
gitleaks detect --source . --redact      # history matters more than the tree
4. 密码存储
Correct:   Argon2id (preferred), scrypt, bcrypt, PBKDF2-HMAC-SHA256 with a
           high iteration count — each with a per-user random salt
Wrong:     MD5, SHA-1, SHA-256, SHA-512 (raw or salted), any unsalted hash,
           encryption instead of hashing, a "pepper" as the only defense

请依据当前指南检查工作因子,而不是沿用代码编写时认为足够的值。还要检查验证流程是否使用了库提供的恒定时间验证函数,而不是直接比较字符串。

5. 随机性

安全相关值——令牌、会话 ID、nonce、盐值、密码重置码、IV——必须由 CSPRNG 生成。

rg -n 'math/rand|Math\.random\(\)|random\.random\(|rand\(\)|mt_rand|Random\(\)' 
# Correct: crypto/rand, secrets.token_bytes, window.crypto.getRandomValues,
#          SecureRandom, os.urandom, RandomNumberGenerator

还要检查:使用时间戳或 PID 作为种子、将基于弱随机源生成的 UUIDv1/v4 用作秘密,以及在需要不可猜测性时使用可预测的连续 ID。

6. 计时侧信道

任何涉及秘密的比较都必须采用恒定时间操作:MAC、令牌、API 签名、密码哈希、OTP。

rg -n 'hmac.*==|token\s*==|signature\s*==|\.equals\(.*(hmac|token|sig)' -i
# Correct: hmac.compare_digest, crypto.timingSafeEqual, subtle.ConstantTimeCompare,
#          MessageDigest.isEqual, hash_equals

对 HMAC 进行会提前返回的字符串比较属于实际可行的远程攻击,并非理论上的问题。

7. 签名验证
  • 是否真正验证了签名,还是仅仅解析了签名?
  • 算法是否取自消息?(JWT alg 混淆:none,以及 RS256→HS256,此时公钥会变成 HMAC 密钥。)
  • 密钥是否通过攻击者可控的标识符(kid、jku、x5u)选取?这些字段由攻击者提供;应据此处理。
  • 签名验证后是否验证了声明:exp、nbf、iss、aud,以及——至关重要的是——主体当前的授权状态?
rg -n 'jwt\.decode\(|verify\s*[:=]\s*(False|false)|algorithms\s*=\s*\[?["\x27]?none' -i
rg -n 'InsecureSkipVerify|verify\s*=\s*False|CURLOPT_SSL_VERIFYPEER.*0|rejectUnauthorized:\s*false'
8. TLS 配置
# Server side
testssl.sh --severity MEDIUM https://target
sslyze --regular target:443
nmap --script ssl-enum-ciphers -p 443 target

# Look for: TLS < 1.2, RC4/3DES/NULL/EXPORT ciphers, no forward secrecy,
# weak DH params, expired or misissued certs, missing HSTS

客户端侧出错的情况比服务端侧更常见。请检查是否启用了证书验证、是否开启了主机名验证(在多个库中,它与证书链验证是分开的),以及自定义信任存储是否会在不知情的情况下接受所有证书。自定义 TrustManager 若返回时不抛出异常,就是 Java 中“完全没有 TLS”的惯用写法。

9. 后量子防护状况

对于机密性需要长期保障的内容,请指出“先窃取、后解密”的风险,以及当前技术栈是否支持混合密钥交换(例如 X25519 + ML-KEM)。这属于路线图发现,通常并非紧急问题——但请明确说明,而不是将其省略。

协议层面的问题

除基础原语外,还应询问:

  • 重放:是否使用了 nonce、时间戳或序列号?是否确实进行了检查和存储?
  • 绑定:签名是否绑定到包含接收方和上下文在内的整条消息?签名剥离和跨协议复用都源于签名范围过窄。
  • 降级:客户端或服务端能否协商到较弱的模式?
  • 预言机:错误处理是否会区分“填充错误”和“MAC 错误”,或区分解密失败和授权失败?任何可观察到的差异——包括时序和响应大小——都可能构成预言机。
  • 规范化:如果签名覆盖的是序列化结构,同一结构是否可能以两种方式序列化?JSON 和 XML 签名方案经常因此出错。

应驳回的托词

  • “它经过加密了。” 加密不等于经过身份验证,也不等于获得授权。
  • “我们使用 AES-256,所以很安全。” 密钥长度几乎从来不是薄弱环节。
  • “IV 足够随机。” 请说明它在哪里生成,以及使用什么方式生成。
  • “通过网络进行时序攻击并不现实。” 这类攻击是现实存在的,而且已在互联网上被反复演示。
  • “因为库用起来不方便,所以我们自己实现了加密。” 自定义加密本身就是一项发现。请指出应该改用哪个库。
  • “密钥放在环境变量中,而不是代码里。” 这样更好,但还需检查环境变量在哪里设置、谁能读取进程环境,以及它是否会出现在日志、崩溃转储或容器映像中。
  • “证书固定太麻烦了。” 可以——但应将其说明为已接受的风险,而不是禁用验证。
  • “这是内部流量。” 横向移动就发生在内部网络中。

交付内容

对于每项发现,请说明:涉及的原语或协议、具体的不当用法、由此可实施的具体攻击(而不是泛泛地说“加密较弱”)、受影响的数据及其机密性期限,以及明确的正确构造方式——包括具体库、模式和参数。仅建议“使用强加密”的加密问题,无法得到修复。

阅读外部来源

以 Markdown 格式获取公开公告、规范和供应商报告:

curl -sL "https://defuddle.md/<url>"      # scheme in the path is optional

这会移除页面冗余内容——对于以正文为主的页面,令牌数大约减少 78%——并返回全文而非摘要,因此你可以搜索内容,并相信搜索无结果的结论。

它不适用于三种情况。获取 JSON 和 API 响应时应保留原始格式,因为可读性提取会破坏结构化数据。获取需要身份验证或由 JavaScript 渲染的页面时,应直接获取,因为它会匿名检索。切勿通过它访问对手基础设施(钓鱼链接、C2、恶意软件托管)、客户端拥有的主机或测试任务 URL——请求会离开你的机器并发往第三方;对于活动中的对手基础设施,这还会向操作者暴露你的访问行为。

有些网站会拦截提取器并返回错误信息,而非页面内容——例如 freedesktop.org 返回的 {"error":"Failed to fetch: 418 I'm a teapot"}。这表示获取请求被拒绝,并不表示来源声称该内容不存在。得出任何结论前,请直接重新获取该 URL。

参考资料

  • auditing-code-for-vulnerabilities — 相关的代码审查
  • cracking-passwords — 弱密码存储的攻击侧
  • testing-apis — API 层的令牌和签名处理
  • 推荐的库:libsodium/NaCl、Google Tink、age、平台 AEAD API
  • testssl.sh、sslyze、cryptography(Python)审计 API、cargo-crev

评论

支持 Markdown