防滥用API与配置分析Skill sharp-edges

用于识别API设计、配置模式和接口中的安全隐患,确保开发者在默认情况下遵循安全最佳实践。关键词:API安全、配置审计、防滥用设计、安全默认值、代码审查、易错识别、威胁建模、安全漏洞预防。

安全审计 0 次安装 0 次浏览 更新于 3/14/2026

name: 锋利边缘分析 description: “识别易错API、危险配置和导致安全错误的易错设计。用于审查API设计、配置模式、加密库可用性,或评估代码是否遵循’默认安全’和’成功陷阱’原则。触发器:易错设计、防滥用、安全默认值、API可用性、危险配置。” allowed-tools:

  • 读取
  • 查找
  • 全局匹配

锋利边缘分析

评估API、配置和接口是否能够抵抗开发者误用。识别设计中的’简单路径’导致不安全的情况。

何时使用

  • 审查API或库设计决策
  • 审计配置模式中的危险选项
  • 评估加密API的可用性
  • 评估认证/授权接口
  • 审查任何向开发者暴露安全相关选择的代码

何时不使用

  • 实现漏洞(使用标准代码审查)
  • 业务逻辑缺陷(使用领域特定分析)
  • 性能优化(不同关注点)

核心原则

成功陷阱:安全使用应该是最小阻力的路径。如果开发者必须理解密码学、仔细阅读文档或记住特殊规则以避免漏洞,API就已经失败。

需要拒绝的合理化

合理化 为什么它是错的 所需行动
“它有文档” 开发者在截止日期压力下不读文档 将安全选择设为默认或唯一选项
“高级用户需要灵活性” 灵活性导致易错设计;大多数’高级’使用是复制粘贴 提供安全的高级API;隐藏原始接口
“这是开发者的责任” 推卸责任;你设计了易错设计 移除易错设计或使其无法误用
“没人会真的这样做” 开发者在压力下会做任何想象到的事情 假设最大程度的开发者混淆
“这只是个配置选项” 配置就是代码;错误配置会部署到生产环境 验证配置;拒绝危险组合
“我们需要向后兼容” 不安全的默认值不能被祖父条款保护 高声弃用;强制迁移

锋利边缘类别

1. 算法/模式选择易错设计

让开发者选择算法的API会邀请错误选择。

JWT模式(典型例子):

  • 头部指定算法:攻击者可以设置"alg": "none"绕过签名
  • 算法混淆:当切换RS256→HS256时,RSA公钥用作HMAC密钥
  • 根本原因:让不受信任的输入控制安全关键决策

检测模式:

  • 函数参数如algorithmmodecipherhash_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=0max_attempts=0key=""时会发生什么?
  • 默认是最安全的选项吗?
  • 任何默认值能否完全禁用安全?

3. 原始API与语义API

暴露原始字节而不是有意义的类型的API会引发类型混淆。

Libsodium vs. Halite模式:

// Libsodium(原始):字节就是字节
sodium_crypto_box($message, $nonce, $keypair);
// 容易:交换nonce/keypair、重用nonce、使用错误密钥类型

// Halite(语义):类型强制正确使用
Crypto::seal($message, new EncryptionPublicKey($key));
// 错误密钥类型 = 类型错误,不是静默失败

检测模式:

  • 函数为不同安全概念取bytesstring[]byte
  • 交换参数而不会引发类型错误的参数
  • 相同类型用于密钥、nonce、密文、签名

比较易错设计:

// 时序安全比较看起来与不安全相同
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"  # 太容易升级

# 对比类型安全
permissions = {Permission.READ, Permission.WRITE}
permissions.add(Permission.ADMIN)  # 至少它是显式的

分析工作流

阶段1:表面识别

  1. 映射安全相关API:认证、授权、密码学、会话管理、输入验证
  2. 识别开发者选择点:开发者可以在哪里选择算法、配置超时、选择模式?
  3. 查找配置模式:环境变量、配置文件、构造函数参数

阶段2:边缘情况探测

对于每个选择点,询问:

  • 零/空/null:使用0""null[]时会发生什么?
  • 负值-1是什么意思?无限?错误?
  • 类型混淆:不同安全概念可以交换吗?
  • 默认值:默认安全吗?有文档吗?
  • 错误路径:无效输入时会发生什么?静默接受?

阶段3:威胁建模

考虑三个对手:

  1. 恶棍:主动恶意开发者或控制配置的攻击者

    • 他们能通过配置禁用安全吗?
    • 他们能降级算法吗?
    • 他们能注入恶意值吗?
  2. 懒惰开发者:复制粘贴示例,跳过文档

    • 他们找到的第一个例子会是安全的吗?
    • 最小阻力的路径安全吗?
    • 错误信息指导安全使用吗?
  3. 混淆开发者:误解API

    • 他们能交换参数而不引发类型错误吗?
    • 他们会意外使用错误密钥/算法/模式吗?
    • 失败模式明显还是静默?

阶段4:验证发现

对于每个识别的锋利边缘:

  1. 重现误用:编写演示易错设计的最小代码
  2. 验证可利用性:误用是否创建真实漏洞?
  3. 检查文档:危险有文档吗?(文档不能为糟糕设计开脱,但影响严重性)
  4. 测试缓解措施:API能否以合理努力安全使用?

如果发现似乎有问题,返回阶段2并探测更多边缘情况。

严重性分类

严重性 标准 示例
严重 默认或明显使用不安全 verify: false默认;允许空密码
容易误配置破坏安全 算法参数接受"none"
不寻常但可能误配置 负超时具有意外含义
需要故意误用 晦涩参数组合

参考文献

按类别:

按语言(一般易错设计,非加密特定):

语言 指南
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