mcpField
S
sharp-edges

sharp-edges

github.com/waybarrios安全54644 次安装1 天前更新
代码仓库

关于 sharp-edges

sharp-edges 是一项安全审查技能,用于评估 API、配置和接口是否便于安全使用。它聚焦不安全默认值、类型混淆和静默失败等误用风险,并提供系统化探查与验证流程。

主要功能

  1. 01审查 API 和配置的误用风险
  2. 02识别不安全默认值与配置陷阱
  3. 03探查边界情况和失败路径
  4. 04通过误用示例验证发现
  5. 05严重性分级与质量检查清单

适用场景

  1. 01审查加密 API 面向开发者的设计
  2. 02评估身份验证与授权接口
  3. 03审计配置选项中的不安全组合

安装

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

$npx skills add https://github.com/waybarrios/opencode-power-pack --skill sharp-edges

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
auth-patterns.md
case-studies.md
config-patterns.md
crypto-apis.md
lang-c.md
lang-csharp.md
lang-go.md
lang-java.md
lang-javascript.md
lang-kotlin.md
lang-php.md
lang-python.md
lang-ruby.md
lang-rust.md
lang-swift.md
language-specific.md

详细介绍

尖锐边缘分析

评估 API、配置和接口能否抵御开发者误用。找出那些会让“不费力的做法”导致安全问题的设计。

适用场景

  • 审查 API 或库的设计决策
  • 审计存在危险选项的配置架构
  • 评估加密 API 的易用性
  • 评估身份验证/授权接口
  • 审查任何向开发者开放安全相关选项的代码

不适用场景

  • 实现错误(使用标准代码审查)
  • 业务逻辑缺陷(使用特定领域的分析)
  • 性能优化(这是另一个关注点)

核心原则

成功之路:安全用法应该是最省力的选择。如果开发者必须理解密码学、仔细阅读文档或记住特殊规则才能避免漏洞,那么这个 API 就失败了。

应驳斥的托词

托词错误之处必须采取的行动
“文档里写了”开发者在截止日期的压力下不会阅读文档将安全选项设为默认选项或唯一选项
“高级用户需要灵活性”灵活性会带来容易踩中的陷阱;多数“高级”用法都是复制粘贴提供安全的高层 API;隐藏底层原语
“这是开发者的责任”推卸责任;这个陷阱是你设计的移除这个陷阱,或让误用变得不可能
“没人会真的那么做”在压力之下,开发者什么都做得出来假设开发者会陷入最大程度的困惑
“这只是一个配置选项”配置就是代码;错误配置会被部署到生产环境验证配置;拒绝危险的组合
“我们需要向后兼容”不安全的默认值不能靠祖传兼容条款保留明确弃用;强制迁移

尖锐边缘类别

1. 算法/模式选择陷阱

允许开发者选择算法的 API,容易导致错误选择。

JWT 模式(经典示例):

  • 请求头指定算法:攻击者可以将 "alg": "none" 设为无算法,从而绕过签名
  • 算法混淆:切换 RS256→HS256 时,将 RSA 公钥用作 HMAC 密钥
  • 根本原因:允许不可信输入控制安全关键决策

检测模式:

  • algorithm、mode、cipher、hash_type 等函数参数
  • 用于选择加密原语的枚举/字符串
  • 用于配置安全机制的选项

示例——允许使用弱算法的 PHP password_hash:

// DANGEROUS: allows crc32, md5, sha1
password_hash($password, PASSWORD_DEFAULT); // Good - no choice
hash($algorithm, $password); // BAD: accepts "crc32"
2. 危险的默认值

不安全的默认值,或会禁用安全功能的零值/空值。

OTP 有效期模式:

# What happens when lifetime=0?
def verify_otp(code, lifetime=300):  # 300 seconds default
    if lifetime == 0:
        return True  # OOPS: 0 means "accept all"?
        # Or does it mean "expired immediately"?

检测模式:

  • 接受 0 的超时/有效期(表示无限期?立即过期?)
  • 绕过检查的空字符串
  • 跳过验证的 null 值
  • 会禁用安全功能的布尔默认值
  • 语义未定义的负值

要提出的问题:

  • timeout=0、max_attempts=0、key="" 会发生什么?
  • 默认值是否是最安全的选项?
  • 是否有任何默认值会彻底禁用安全功能?
3. 原语 API 与语义化 API

暴露原始字节而非有意义类型的 API,容易引发类型混淆。

Libsodium 与 Halite 模式:

// Libsodium (primitives): bytes are bytes
sodium_crypto_box($message, $nonce, $keypair);
// Easy to: swap nonce/keypair, reuse nonces, use wrong key type

// Halite (semantic): types enforce correct usage
Crypto::seal($message, new EncryptionPublicKey($key));
// Wrong key type = type error, not silent failure

检测模式:

  • 使用 bytes、string、[]byte 表示不同安全概念的函数
  • 即使没有类型错误也可能被互换的参数
  • 密钥、随机数、密文和签名使用相同类型

比较操作陷阱:

// Timing-safe comparison looks identical to unsafe
if hmac == expected { }           // BAD: timing attack
if hmac.Equal(mac, expected) { }  // Good: constant-time
// Same types, different security properties
4. 配置陷阱

一个错误的设置就会导致灾难性故障,且没有任何警告。

检测模式:

  • 会完全禁用安全性的布尔标志
  • 未经过验证的字符串配置
  • 彼此交互并带来危险后果的设置组合
  • 会覆盖安全设置的环境变量
  • 默认值合理但未经验证的构造函数参数(调用方可以将其覆盖为不安全的值)

示例:

# One typo = disaster
verify_ssl: fasle  # Typo silently accepted as truthy?

# Magic values
session_timeout: -1  # Does this mean "never expire"?

# Dangerous combinations accepted silently
auth_required: true
bypass_auth_for_health_checks: true
health_check_path: "/"  # Oops
// Sensible default doesn't protect against bad callers
public function __construct(
    public string $hashAlgo = 'sha256',  // Good default...
    public int $otpLifetime = 120,       // ...but accepts md5, 0, etc.
) {}

详细模式请参阅 config-patterns.md。

5. 静默失败

错误未能显现,或成功掩盖了失败。

检测模式:

  • 安全操作失败时返回布尔值,而不是抛出异常的函数
  • 安全操作周围的空 catch 块
  • 解析错误时用默认值替代
  • 对格式错误的输入也会“成功”的验证函数

示例:

# Silent bypass
def verify_signature(sig, data, key):
    if not key:
        return True  # No key = skip verification?!

# Return value ignored
signature.verify(data, sig)  # Throws on failure
crypto.verify(data, sig)     # Returns False on failure
# Developer forgets to check return value
6. 字符串化安全

将安全关键值设为普通字符串,会导致注入和混淆。

检测模式:

  • 通过拼接字符串构造 SQL/命令
  • 用逗号分隔的字符串表示权限
  • 用任意字符串而非枚举表示角色/范围
  • 通过拼接字符串构造 URL

权限累积陷阱:

permissions = "read,write"
permissions += ",admin"  # Too easy to escalate

# vs. type-safe
permissions = {Permission.READ, Permission.WRITE}
permissions.add(Permission.ADMIN)  # At least it's explicit

分析工作流

阶段 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
Goreferences/lang-go.md
Rustreferences/lang-rust.md
Swiftreferences/lang-swift.md
Javareferences/lang-java.md
Kotlinreferences/lang-kotlin.md
C#references/lang-csharp.md
PHPreferences/lang-php.md
JavaScript/TypeScriptreferences/lang-javascript.md
Pythonreferences/lang-python.md
Rubyreferences/lang-ruby.md

另请参见 references/language-specific.md,了解综合快速参考。

质量检查清单

完成分析前:

  • 探测所有零值/空值/null 边界情况
  • 验证默认值是否安全
  • 检查算法/模式选择中的易错点
  • 测试安全概念之间的类型混淆
  • 考虑所有三类对手
  • 验证错误处理路径不会绕过安全措施
  • 检查配置验证
  • 验证构造函数参数(而非仅设置默认值)——参见 config-patterns.md

评论

支持 Markdown