关于 cryptographic-failures
用于审查 Python 应用加密失效问题的安全技能,结合 Bandit 静态扫描、代码模式检查和修复建议,覆盖常见加密风险。
主要功能
- 01使用 Bandit 扫描加密问题
- 02检查密码哈希与随机数
- 03排查硬编码密钥和 TLS 验证
- 04审查 JWT 与对称加密
- 05提供 Python 框架专项指导
适用场景
- 01审计 Python 代码中的弱加密
- 02检查令牌和密码处理
- 03核查 TLS 与证书验证
- 04指导修复加密问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ scholarly360/ owasp-top10-web-skills --skill cryptographic-failures安装后在 Claude Code 中输入/cryptographic-failures确认已加载。
附带文件references/owasp-a04-full.md
详细介绍
A04:2025 — 加密失效
OWASP 排名: 第 4 位(因 TLS 采用率提升,从第 2 位下降) 发生率: 3.80% 的应用,超过 160 万次,涉及 32 个 CWE
加密失效指用于保护静态和传输中数据的加密技术缺失、使用不当或强度不足。Python 中有一系列独特的陷阱,与 Java/.NET 中的情况有所不同。
本技能涵盖的内容
| 领域 | 主要风险 | Python 特有陷阱 |
|---|---|---|
| 密码哈希 | 算法强度不足或缺失 | 使用 hashlib.md5/sha1,而非 bcrypt/Argon2 |
| 随机性 | 值可预测 | 使用 import random,而非 import secrets |
| 硬编码密钥 | 密钥泄露 | 在源代码中使用 SECRET_KEY = "..." 字面值 |
| TLS/SSL | 绕过证书验证 | 在 requests/httpx 中使用 verify=False |
| JWT 密钥 | 密钥强度/算法 | 密钥强度不足,未固定算法 |
| 对称加密 | 已弃用的模式 | ECB 模式,未使用经过身份验证的加密 |
逐步审计工作流
1. 使用 Bandit 进行静态扫描
运行 Bandit——这是用于自动检测加密问题的主要 Python SAST 工具:
pip install bandit
bandit -r . -t B303,B304,B305,B306,B311,B324,B501,B502,B503,B504,B505,B506 -f json -o bandit_crypto.json
与加密失效相关的 Bandit 测试 ID:
| Bandit ID | 检测内容 | 严重性 |
|---|---|---|
| B303 | 使用 MD5/SHA1 | 中 |
| B304/B305 | 弱加密模式(ECB、DES) | 高 |
| B311 | 在安全相关场景中使用 random 模块 | 低 |
| B324 | 使用 hashlib 的弱哈希 | 中 |
| B501 | 在 SSL 上下文中使用 verify=False | 高 |
| B502/B503/B504 | 不安全的 SSL/TLS 版本 | 中–高 |
| B105/B106 | 硬编码密码/密钥 | 中 |
2. 手动检查代码模式
按优先级依次检查以下模式:
🔴 严重 — 密码哈希
# BAD — MD5/SHA1 for passwords: CWE-328, CWE-759, CWE-916
hashlib.md5(password.encode()).hexdigest()
hashlib.sha1(password.encode()).hexdigest()
hashlib.sha256(password.encode()).hexdigest() # also bad — no salt, no stretching
# GOOD — use passlib with bcrypt or argon2
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
# OR
pwd_context = CryptContext(schemes=["bcrypt"], bcrypt__rounds=12, deprecated="auto")
hashed = pwd_context.hash(plain_password)
检查以下情况:
- 使用任何
hashlib.*调用对密码或令牌进行哈希 - 缺少盐值(未使用
hashlib.pbkdf2_hmac,直接对原始密码进行哈希) - bcrypt 的
rounds < 12——应为 ≥12,以抵御暴力破解
🔴 严重 — 随机性不足(CWE-330)
# BAD — random is NOT cryptographically secure
import random
token = random.randint(100000, 999999) # predictable OTP
reset_key = random.choice(string.ascii_letters + string.digits) # guessable
# GOOD
import secrets
token = secrets.randbelow(900000) + 100000 # secure OTP
reset_key = secrets.token_urlsafe(32) # secure reset token
session_id = secrets.token_hex(16) # secure session ID
检查以下情况: 在涉及令牌、OTP、会话 ID、密钥或随机数的代码路径中,使用了任何 random.random()、random.randint()、random.choice()、random.shuffle()。
🔴 高 — 硬编码的加密密钥(CWE-321)
# BAD — key in source code
SECRET_KEY = "my-super-secret-key"
JWT_SECRET = "hardcoded_jwt_secret_123"
app.config['SECRET_KEY'] = "flask_secret"
# GOOD — load from environment
import os
SECRET_KEY = os.environ["SECRET_KEY"] # raises KeyError if missing (intentional)
SECRET_KEY = os.getenv("SECRET_KEY") # returns None silently (verify it's not None)
最低密钥长度:
- Flask
SECRET_KEY:≥32 个随机字节(使用secrets.token_hex(32)) - JWT HMAC 密钥:≥32 个字符
- AES 密钥:128、192 或 256 位(16、24 或 32 字节)
🔴 高 — 绕过 TLS/SSL 证书验证(CWE-295)
# BAD — disables certificate validation entirely
requests.get(url, verify=False)
httpx.get(url, verify=False)
ssl._create_unverified_context()
urllib3.disable_warnings() # companion to verify=False
# GOOD
requests.get(url) # verify=True is the default
requests.get(url, verify="/path/to/ca-bundle.crt") # custom CA
🟡 中 — JWT 配置(CWE-327)
# BAD — algorithm confusion attacks
jwt.decode(token, key, algorithms=["none"]) # NEVER allow "none"
jwt.decode(token, key) # no algorithm pin = vulnerable
# BAD — weak secret loaded without validation
JWT_SECRET = os.getenv("JWT_SECRET", "default") # fallback default is dangerous
# GOOD
JWT_SECRET = os.environ["JWT_SECRET"] # fail hard if missing
assert len(JWT_SECRET) >= 32, "JWT secret too short"
jwt.decode(token, JWT_SECRET, algorithms=["HS256"]) # explicit allowlist
另请检查:
- 令牌过期时间(
exp声明)——访问令牌应为 15–30 分钟 - 解码时会验证
aud和iss声明
🟡 中 — 已弃用的对称加密(CWE-327)
# BAD — ECB mode leaks patterns in data
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_ECB)
# BAD — no authentication = vulnerable to tampering
cipher = AES.new(key, AES.MODE_CBC, iv)
# GOOD — authenticated encryption
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
# ChaCha20-Poly1305 is also acceptable
FastAPI 特定检查
# 1. Verify OAuth2/JWT middleware algorithm pinning
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
ALGORITHM = "HS256" # must be explicit, not a variable that could be overridden
# Check: is ALGORITHM loaded from config where it could be tampered with?
# 2. Verify password hashing in user creation/login endpoints
@router.post("/register")
async def register(user: UserCreate, db: Session = Depends(get_db)):
hashed = pwd_context.hash(user.password) # must NOT store plain or MD5
# 3. Token generation for password resets / email verification
def generate_reset_token() -> str:
return secrets.token_urlsafe(32) # GOOD
# NOT: str(uuid.uuid4()) — UUID v4 uses os.urandom, acceptable but secrets is preferred
# NOT: random-based anything
Flask 特定检查
# 1. Session cookie signing uses SECRET_KEY — must be strong
app.secret_key = os.environ["SECRET_KEY"] # GOOD
app.secret_key = "dev" # BAD — common in tutorials, dangerous in prod
# 2. Flask-Login password verification
from flask_bcrypt import Bcrypt
bcrypt = Bcrypt(app)
bcrypt.generate_password_hash(password, rounds=12) # rounds≥12
# 3. HTTPS enforcement via HSTS
from flask_talisman import Talisman
Talisman(app, force_https=True) # adds HSTS header
关键 CWE 参考
| CWE | 名称 | 常见表现 |
|---|---|---|
| CWE-327 | 使用已破解/有风险的加密算法 | MD5、SHA1、ECB、DES、RC4 |
| CWE-328 | 可逆的单向哈希 | 将 MD5/SHA1 用于密码(可通过彩虹表还原) |
| CWE-330 | 随机值不足 | 使用 random 模块生成令牌/密钥 |
| CWE-321 | 硬编码的加密密钥 | 密钥写在源代码中 |
| CWE-759 | 单向哈希未使用盐值 | hashlib.sha256(password)——没有盐值 |
| CWE-916 | 密码哈希所用计算量不足 | bcrypt rounds<12,PBKDF2 迭代次数<600k |
| CWE-295 | 证书验证不当 | 在 HTTP 客户端中使用 verify=False |
修复检查清单
Python 2025 最低可行加密技术栈
Password hashing: passlib[argon2] or passlib[bcrypt] (rounds≥12)
Token generation: secrets module exclusively
Symmetric crypto: cryptography library, AES-GCM or ChaCha20-Poly1305
JWT: python-jose or PyJWT, algorithm pinned, secret≥32 chars
TLS: verify=True always; pin CA bundle where needed
Config/secrets: os.environ (fail-hard) or a secrets manager (Vault, AWS SSM)
HSTS: flask-talisman (Flask) or custom middleware (FastAPI)
用于代码搜索的快速正则表达式
# Find weak hashing
grep -rn "hashlib\.md5\|hashlib\.sha1\|hashlib\.sha224" --include="*.py"
# Find insecure random
grep -rn "import random\b" --include="*.py"
grep -rn "random\.randint\|random\.choice\|random\.random()" --include="*.py"
# Find hardcoded secrets
grep -rn "SECRET_KEY\s*=\s*['\"]" --include="*.py"
grep -rn "verify=False" --include="*.py"
# Find ECB mode
grep -rn "MODE_ECB\|AES\.MODE_ECB" --include="*.py"
另请参阅
references/owasp-a04-full.md— 完整的 OWASP A04:2025 规范及扩展 CWE 列表- 有关供应链加密问题(固定依赖哈希),请参阅
software-supply-chain技能 - 有关超出加密范畴的 JWT 身份验证逻辑(过期时间、声明),请参阅
authentication-failures技能
评论
支持 Markdown