名称: 锐利边缘分析 描述: “识别易出错的API、危险配置和易误用设计,使开发者能够犯下安全错误。用于审查API设计、配置模式、密码学库的易用性,或评估代码是否遵循’默认安全’和’成功之路’原则。触发词:易误用、抗滥用、安全默认值、API可用性、危险配置。” 允许工具:
- 读取
- 搜索
- 通配符
锐利边缘分析
评估API、配置和接口是否抗开发者误用。识别设计中的’简单路径’导致不安全的情况。
何时使用
- 审查API或库设计决策
- 审计配置模式中的危险选项
- 评估密码学API的易用性
- 评估身份验证/授权接口
- 审查任何向开发者暴露安全相关选择的代码
何时不使用
- 实现缺陷(使用标准代码审查)
- 业务逻辑漏洞(使用特定领域分析)
- 性能优化(不同关注点)
核心原则
成功之路:安全使用应该是最少阻力的路径。如果开发者必须理解密码学、仔细阅读文档或记住特殊规则来避免漏洞,则API设计失败。
需要拒绝的合理化
| 合理化 | 为什么错误 | 所需行动 |
|---|---|---|
| “有文档说明” | 开发者在截止日期压力下不阅读文档 | 使安全选择成为默认或唯一选项 |
| “高级用户需要灵活性” | 灵活性创建易误用;大多数’高级’使用是复制粘贴 | 提供安全高层API;隐藏原始操作 |
| “是开发者的责任” | 推卸责任;您设计了易误用 | 移除易误用或使其不可能误用 |
| “没有人会真的那样做” | 开发者在压力下会做任何想象得到的事 | 假设最大开发者混淆 |
| “这只是一个配置选项” | 配置是代码;错误配置会部署到生产环境 | 验证配置;拒绝危险组合 |
| “我们需要向后兼容” | 不安全默认不能永远保留 | 大声弃用;强制迁移 |
锐利边缘类别
1. 算法/模式选择易误用
允许开发者选择算法的API会诱使他们选择错误算法。
JWT模式(典型示例):
- 头部指定算法:攻击者可以设置
"alg": "none"来绕过签名 - 算法混淆:切换RS256→HS256时,RSA公钥被用作HMAC密钥
- 根本原因:让不受信任的输入控制安全关键决策
检测模式:
- 函数参数如
algorithm、mode、cipher、hash_type - 枚举/字符串选择密码学原语
- 安全机制的配置选项
示例 - PHP password_hash 允许弱算法:
// 危险:允许crc32、md5、sha1
password_hash($password, PASSWORD_DEFAULT); // 好 - 无选择
hash($algorithm, $password); // 坏:接受"crc32"
2. 危险默认值
不安全默认值,或零/空值禁用安全。
OTP生命周期模式:
# 当lifetime=0时会发生什么?
def verify_otp(code, lifetime=300): # 300秒默认值
if lifetime == 0:
return True # 糟糕:0表示'接受所有'?
# 或表示'立即过期'?
检测模式:
- 接受0的超时/生命周期(无限?立即过期?)
- 空字符串绕过检查
- null值跳过验证
- 布尔默认值禁用安全功能
- 负值语义未定义
要问的问题:
timeout=0、max_attempts=0、key=""时会发生什么?- 默认值是最安全选项吗?
- 任何默认值会完全禁用安全吗?
3. 原始API与语义API
暴露原始字节而非有意义类型的API容易导致类型混淆。
Libsodium vs. Halite模式:
// Libsodium(原始操作):字节就是字节
sodium_crypto_box($message, $nonce, $keypair);
// 容易:交换nonce/keypair、重用nonces、使用错误密钥类型
// Halite(语义):类型强制正确使用
Crypto::seal($message, new EncryptionPublicKey($key));
// 错误密钥类型 = 类型错误,而非静默失败
检测模式:
- 函数接受
bytes、string、[]byte用于不同安全概念 - 参数可交换而不报类型错误
- 相同类型用于密钥、nonces、密文、签名
比较易误用:
// 时间安全比较看起来与不安全相同
if hmac == expected { } // 坏:时间攻击
if hmac.Equal(mac, expected) { } // 好:恒定时间
// 相同类型,不同安全属性
4. 配置悬崖
一个错误设置导致灾难性失败,无警告。
检测模式:
- 布尔标志完全禁用安全
- 字符串配置未验证
- 设置组合危险交互
- 环境变量覆盖安全设置
- 构造函数参数有合理默认值但无验证(调用者可用不安全值覆盖)
示例:
# 一个拼写错误 = 灾难
verify_ssl: fasle # 拼写错误被静默接受为真?
# 魔法值
session_timeout: -1 # 这表示'永不过期'?
# 危险组合被静默接受
auth_required: true
bypass_auth_for_health_checks: true
health_check_path: "/" # 糟糕
// 合理默认值不保护坏调用者
public function __construct(
public string $hashAlgo = 'sha256', // 好默认值...
public int $otpLifetime = 120, // ...但接受md5、0等。
) {}
参见 config-patterns.md 获取详细模式。
5. 静默失败
错误不浮现,或成功掩盖失败。
检测模式:
- 函数返回布尔值而非在安全失败时抛出异常
- 安全操作周围的空catch块
- 解析错误时替换默认值
- 验证函数在输入格式错误时’成功’
示例:
# 静默绕过
def verify_signature(sig, data, key):
if not key:
return True # 无密钥 = 跳过验证?!
# 返回值被忽略
signature.verify(data, sig) # 失败时抛出异常
crypto.verify(data, sig) # 失败时返回False
# 开发者忘记检查返回值
6. 字符串类型安全
安全关键值作为纯字符串启用注入和混淆。
检测模式:
- SQL/命令从字符串连接构建
- 权限作为逗号分隔字符串
- 角色/范围作为任意字符串而非枚举
- URL通过连接字符串构造
权限累积易误用:
permissions = "read,write"
permissions += ",admin" # 太容易升级
# vs. 类型安全
permissions = {Permission.READ, Permission.WRITE}
permissions.add(Permission.ADMIN) # 至少它是明确的
分析工作流程
阶段1:表面识别
- 映射安全相关API:身份验证、授权、密码学、会话管理、输入验证
- 识别开发者选择点:开发者在何处可以选择算法、配置超时、选择模式?
- 找到配置模式:环境变量、配置文件、构造函数参数
阶段2:边缘情况探测
对于每个选择点,询问:
- 零/空/null:
0、""、null、[]时会发生什么? - 负值:
-1表示什么?无限?错误? - 类型混淆:不同安全概念可交换吗?
- 默认值:默认值安全吗?有文档说明吗?
- 错误路径:无效输入时会发生什么?静默接受?
阶段3:威胁建模
考虑三个对手:
-
恶棍:主动恶意开发者或控制配置的攻击者
- 他们能通过配置禁用安全吗?
- 他们能降级算法吗?
- 他们能注入恶意值吗?
-
懒惰开发者:复制粘贴示例,跳过文档
- 他们找到的第一个例子安全吗?
- 最少阻力的路径安全吗?
- 错误消息引导向安全使用吗?
-
困惑开发者:误解API
- 他们能不报类型错误交换参数吗?
- 他们会意外使用错误密钥/算法/模式吗?
- 失败模式明显还是静默?
阶段4:验证发现
对于每个识别的锐利边缘:
- 重现误用:编写最小代码演示易误用
- 验证可利用性:误用会创建真实漏洞吗?
- 检查文档:危险有文档说明吗?(文档不解释坏设计,但影响严重性)
- 测试缓解措施:API能以合理努力安全使用吗?
如果发现似乎有问题,返回到阶段2并探测更多边缘情况。
严重性分类
| 严重性 | 标准 | 示例 |
|---|---|---|
| 严重 | 默认或明显使用不安全 | verify: false默认;空密码允许 |
| 高 | 容易误配置破坏安全 | 算法参数接受"none" |
| 中 | 不寻常但可能误配置 | 负超时有意外含义 |
| 低 | 需要故意误用 | 晦涩参数组合 |
参考
按类别:
- 密码学API:参见 references/crypto-apis.md
- 配置模式:参见 references/config-patterns.md
- 身份验证/会话:参见 references/auth-patterns.md
- 真实世界案例研究:参见 references/case-studies.md(OpenSSL、GMP等)
按语言(一般易误用,非密码学特定):
| 语言 | 指南 |
|---|---|
| C/C++ | references/lang-c.md |
| Go | references/lang-go.md |
| Rust | references/lang-rust.md |
| Swift | references/lang-swift.md |
| Java | references/lang-java.md |
| Kotlin | references/lang-kotlin.md |
| C# | references/lang-csharp.md |
| PHP | references/lang-php.md |
| JavaScript/TypeScript | references/lang-javascript.md |
| Python | references/lang-python.md |
| Ruby | references/lang-ruby.md |
另见 references/language-specific.md 获取组合快速参考。
质量检查清单
在结束分析前:
- [ ] 探测所有零/空/null边缘情况
- [ ] 验证默认值安全
- [ ] 检查算法/模式选择易误用
- [ ] 测试安全概念间类型混淆
- [ ] 考虑所有三种对手类型
- [ ] 验证错误路径不绕过安全
- [ ] 检查配置验证
- [ ] 构造函数参数已验证(非仅默认) - 见 config-patterns.md