sharp-edges

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Sharp Edges Analysis

尖锐边缘分析

Evaluates whether APIs, configurations, and interfaces are resistant to developer misuse. Identifies designs where the "easy path" leads to insecurity.
评估API、配置和接口是否能抵御开发者误用。识别那些“便捷路径”会导致不安全的设计。

When to Use

适用场景

  • Reviewing API or library design decisions
  • Auditing configuration schemas for dangerous options
  • Evaluating cryptographic API ergonomics
  • Assessing authentication/authorization interfaces
  • Reviewing any code that exposes security-relevant choices to developers
  • 审查API或库的设计决策
  • 审计配置架构中的危险选项
  • 评估加密API的易用性
  • 评估认证/授权接口
  • 审查任何向开发者暴露安全相关选项的代码

When NOT to Use

不适用场景

  • Implementation bugs (use standard code review)
  • Business logic flaws (use domain-specific analysis)
  • Performance optimization (different concern)
  • 实现漏洞(使用标准代码审查)
  • 业务逻辑缺陷(使用领域特定分析)
  • 性能优化(属于不同关注点)

Core Principle

核心原则

The pit of success: Secure usage should be the path of least resistance. If developers must understand cryptography, read documentation carefully, or remember special rules to avoid vulnerabilities, the API has failed.
成功之坑:安全用法应是阻力最小的路径。如果开发者必须理解加密技术、仔细阅读文档或记住特殊规则才能避免漏洞,那么这个API就是失败的。

Rationalizations to Reject

需拒绝的合理化借口

RationalizationWhy It's WrongRequired Action
"It's documented"Developers don't read docs under deadline pressureMake the secure choice the default or only option
"Advanced users need flexibility"Flexibility creates footguns; most "advanced" usage is copy-pasteProvide safe high-level APIs; hide primitives
"It's the developer's responsibility"Blame-shifting; you designed the footgunRemove the footgun or make it impossible to misuse
"Nobody would actually do that"Developers do everything imaginable under pressureAssume maximum developer confusion
"It's just a configuration option"Config is code; wrong configs ship to productionValidate configs; reject dangerous combinations
"We need backwards compatibility"Insecure defaults can't be grandfather-clausedDeprecate loudly; force migration
合理化借口错误原因必要措施
“有文档说明”开发者在截止日期压力下不会阅读文档将安全选项设为默认或唯一选项
“高级用户需要灵活性”灵活性会制造陷阱;大多数“高级”用法都是复制粘贴提供安全的高层API;隐藏底层原语
“这是开发者的责任”推卸责任;是你设计了陷阱移除陷阱或使其无法被误用
“没人真的会那么做”开发者在压力下会做出各种想象得到的操作假设开发者会完全混淆
“这只是一个配置选项”配置也是代码;错误的配置会被部署到生产环境验证配置;拒绝危险组合
“我们需要向后兼容性”不安全的默认值不能被“ grandfathered”(保留旧版本权限)大声宣布弃用;强制迁移

Sharp Edge Categories

尖锐边缘类别

1. Algorithm/Mode Selection Footguns

1. 算法/模式选择陷阱

APIs that let developers choose algorithms invite choosing wrong ones.
The JWT Pattern (canonical example):
  • Header specifies algorithm: attacker can set
    "alg": "none"
    to bypass signatures
  • Algorithm confusion: RSA public key used as HMAC secret when switching RS256→HS256
  • Root cause: Letting untrusted input control security-critical decisions
Detection patterns:
  • Function parameters like
    algorithm
    ,
    mode
    ,
    cipher
    ,
    hash_type
  • Enums/strings selecting cryptographic primitives
  • Configuration options for security mechanisms
Example - PHP password_hash allowing weak algorithms:
php
// DANGEROUS: allows crc32, md5, sha1
password_hash($password, PASSWORD_DEFAULT); // Good - no choice
hash($algorithm, $password); // BAD: accepts "crc32"
允许开发者选择算法的API会导致他们选错。
JWT模式(典型示例):
  • 头部指定算法:攻击者可以设置
    "alg": "none"
    以绕过签名
  • 算法混淆:当从RS256切换到HS256时,RSA公钥被用作HMAC密钥
  • 根本原因:让不可信输入控制安全关键决策
检测模式
  • 包含
    algorithm
    mode
    cipher
    hash_type
    等的函数参数
  • 选择加密原语的枚举/字符串
  • 安全机制的配置选项
示例 - PHP password_hash允许弱算法:
php
// 危险:允许crc32、md5、sha1
password_hash($password, PASSWORD_DEFAULT); // 安全 - 无选择空间
hash($algorithm, $password); // 危险:接受"crc32"

2. Dangerous Defaults

2. 危险默认值

Defaults that are insecure, or zero/empty values that disable security.
The OTP Lifetime Pattern:
python
undefined
不安全的默认值,或会禁用安全功能的零/空值。
OTP生命周期模式:
python
undefined

What happens when lifetime=0?

当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"?

**Detection patterns:**
- Timeouts/lifetimes that accept 0 (infinite? immediate expiry?)
- Empty strings that bypass checks
- Null values that skip validation
- Boolean defaults that disable security features
- Negative values with undefined semantics

**Questions to ask:**
- What happens with `timeout=0`? `max_attempts=0`? `key=""`?
- Is the default the most secure option?
- Can any default value disable security entirely?
def verify_otp(code, lifetime=300): # 默认300秒 if lifetime == 0: return True # 糟糕:0意味着“接受所有”? # 还是意味着“立即过期”?

**检测模式**:
- 接受0的超时/生命周期(无限?立即过期?)
- 绕过检查的空字符串
- 跳过验证的Null值
- 禁用安全功能的布尔默认值
- 语义未定义的负值

**需询问的问题:**
- `timeout=0`、`max_attempts=0`、`key=""`时会发生什么?
- 默认值是最安全的选项吗?
- 任何默认值是否会完全禁用安全功能?

3. Primitive vs. Semantic APIs

3. 原语API vs 语义API

APIs that expose raw bytes instead of meaningful types invite type confusion.
The Libsodium vs. Halite Pattern:
php
// 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
Detection patterns:
  • Functions taking
    bytes
    ,
    string
    ,
    []byte
    for distinct security concepts
  • Parameters that could be swapped without type errors
  • Same type used for keys, nonces, ciphertexts, signatures
The comparison footgun:
go
// 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
暴露原始字节而非有意义类型的API会引发类型混淆。
Libsodium vs Halite模式:
php
// Libsodium(原语):字节就是字节
sodium_crypto_box($message, $nonce, $keypair);
// 容易出现:交换nonce/密钥对、重用nonce、使用错误密钥类型

// Halite(语义):类型强制正确用法
Crypto::seal($message, new EncryptionPublicKey($key));
// 错误密钥类型 = 类型错误,而非静默失败
检测模式
  • 为不同安全概念接受
    bytes
    string
    []byte
    的函数
  • 无需类型错误即可交换的参数
  • 密钥、nonce、密文、签名使用相同类型
比较陷阱:
go
// 计时安全的比较与不安全的比较看起来相同
if hmac == expected { }           // 危险:计时攻击
if hmac.Equal(mac, expected) { }  // 安全:恒定时间
// 相同类型,不同安全属性

4. Configuration Cliffs

4. 配置悬崖

One wrong setting creates catastrophic failure, with no warning.
Detection patterns:
  • Boolean flags that disable security entirely
  • String configs that aren't validated
  • Combinations of settings that interact dangerously
  • Environment variables that override security settings
  • Constructor parameters with sensible defaults but no validation (callers can override with insecure values)
Examples:
yaml
undefined
一个错误设置会导致灾难性故障,且无任何警告。
检测模式
  • 完全禁用安全功能的布尔标志
  • 未验证的字符串配置
  • 交互危险的设置组合
  • 覆盖安全设置的环境变量
  • 具有合理默认值但未验证的构造函数参数(调用者可以用不安全值覆盖)
示例:
yaml
undefined

One typo = disaster

一个拼写错误 = 灾难

verify_ssl: fasle # Typo silently accepted as truthy?
verify_ssl: fasle # 拼写错误是否会被当作真值接受?

Magic values

魔法值

session_timeout: -1 # Does this mean "never expire"?
session_timeout: -1 # 这是否意味着“永不过期”?

Dangerous combinations accepted silently

危险组合被静默接受

auth_required: true bypass_auth_for_health_checks: true health_check_path: "/" # Oops

```php
// 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.
) {}
See config-patterns.md for detailed patterns.
auth_required: true bypass_auth_for_health_checks: true health_check_path: "/" # 糟糕

```php

5. Silent Failures

合理的默认值无法防范错误的调用者

Errors that don't surface, or success that masks failure.
Detection patterns:
  • Functions returning booleans instead of throwing on security failures
  • Empty catch blocks around security operations
  • Default values substituted on parse errors
  • Verification functions that "succeed" on malformed input
Examples:
python
undefined
public function __construct( public string $hashAlgo = 'sha256', // 好的默认值... public int $otpLifetime = 120, // ...但接受md5、0等 ) {}

详见[config-patterns.md](references/config-patterns.md#unvalidated-constructor-parameters)获取详细模式。

Silent bypass

5. 静默失败

def verify_signature(sig, data, key): if not key: return True # No key = skip verification?!
错误不显现,或成功掩盖了失败。
检测模式
  • 安全失败时返回布尔值而非抛出异常的函数
  • 安全操作周围的空catch块
  • 解析错误时代入默认值
  • 对畸形输入“成功”验证的函数
示例:
python
undefined

Return value ignored

静默绕过

signature.verify(data, sig) # Throws on failure crypto.verify(data, sig) # Returns False on failure
def verify_signature(sig, data, key): if not key: return True # 无密钥 = 跳过验证?!

Developer forgets to check return value

返回值被忽略

undefined
signature.verify(data, sig) # 失败时抛出异常 crypto.verify(data, sig) # 失败时返回False

6. Stringly-Typed Security

开发者忘记检查返回值

Security-critical values as plain strings enable injection and confusion.
Detection patterns:
  • SQL/commands built from string concatenation
  • Permissions as comma-separated strings
  • Roles/scopes as arbitrary strings instead of enums
  • URLs constructed by joining strings
The permission accumulation footgun:
python
permissions = "read,write"
permissions += ",admin"  # Too easy to escalate
undefined

vs. type-safe

6. 字符串化安全

permissions = {Permission.READ, Permission.WRITE} permissions.add(Permission.ADMIN) # At least it's explicit
undefined
安全关键值作为普通字符串会导致注入和混淆。
检测模式
  • 通过字符串拼接构建SQL/命令
  • 权限作为逗号分隔的字符串
  • 角色/范围作为任意字符串而非枚举
  • 通过拼接字符串构造URL
权限累积陷阱:
python
permissions = "read,write"
permissions += ",admin"  # 太容易升级权限

Analysis Workflow

vs. 类型安全

Phase 1: Surface Identification

  1. Map security-relevant APIs: authentication, authorization, cryptography, session management, input validation
  2. Identify developer choice points: Where can developers select algorithms, configure timeouts, choose modes?
  3. Find configuration schemas: Environment variables, config files, constructor parameters
permissions = {Permission.READ, Permission.WRITE} permissions.add(Permission.ADMIN) # 至少是显式的
undefined

Phase 2: Edge Case Probing

分析流程

阶段1:表面识别

For each choice point, ask:
  • Zero/empty/null: What happens with
    0
    ,
    ""
    ,
    null
    ,
    []
    ?
  • Negative values: What does
    -1
    mean? Infinite? Error?
  • Type confusion: Can different security concepts be swapped?
  • Default values: Is the default secure? Is it documented?
  • Error paths: What happens on invalid input? Silent acceptance?
  1. 映射安全相关API:认证、授权、加密、会话管理、输入验证
  2. 识别开发者选择点:开发者可以选择算法、配置超时、选择模式的位置?
  3. 查找配置架构:环境变量、配置文件、构造函数参数

Phase 3: Threat Modeling

阶段2:边缘情况探查

Consider three adversaries:
  1. The Scoundrel: Actively malicious developer or attacker controlling config
    • Can they disable security via configuration?
    • Can they downgrade algorithms?
    • Can they inject malicious values?
  2. The Lazy Developer: Copy-pastes examples, skips documentation
    • Will the first example they find be secure?
    • Is the path of least resistance secure?
    • Do error messages guide toward secure usage?
  3. The Confused Developer: Misunderstands the API
    • Can they swap parameters without type errors?
    • Can they use the wrong key/algorithm/mode by accident?
    • Are failure modes obvious or silent?
对于每个选择点,询问:
  • 零/空/Null
    0
    ""
    null
    []
    会发生什么?
  • 负值
    -1
    意味着什么?无限?错误?
  • 类型混淆:不同安全概念是否可以被交换?
  • 默认值:默认值是否安全?是否有文档说明?
  • 错误路径:输入无效时会发生什么?静默接受?

Phase 4: Validate Findings

阶段3:威胁建模

For each identified sharp edge:
  1. Reproduce the misuse: Write minimal code demonstrating the footgun
  2. Verify exploitability: Does the misuse create a real vulnerability?
  3. Check documentation: Is the danger documented? (Documentation doesn't excuse bad design, but affects severity)
  4. Test mitigations: Can the API be used safely with reasonable effort?
If a finding seems questionable, return to Phase 2 and probe more edge cases.
考虑三类攻击者:
  1. 恶棍:主动恶意的开发者或控制配置的攻击者
    • 他们能否通过配置禁用安全功能?
    • 他们能否降级算法?
    • 他们能否注入恶意值?
  2. 懒惰开发者:复制粘贴示例,跳过文档
    • 他们找到的第一个示例是否安全?
    • 阻力最小的路径是否安全?
    • 错误消息是否引导他们使用安全用法?
  3. 困惑开发者:误解API
    • 他们能否无类型错误地交换参数?
    • 他们是否会意外使用错误的密钥/算法/模式?
    • 失败模式是明显的还是静默的?

Severity Classification

阶段4:验证发现

SeverityCriteriaExamples
CriticalDefault or obvious usage is insecure
verify: false
default; empty password allowed
HighEasy misconfiguration breaks securityAlgorithm parameter accepts "none"
MediumUnusual but possible misconfigurationNegative timeout has unexpected meaning
LowRequires deliberate misuseObscure parameter combination
对于每个识别出的尖锐边缘:
  1. 重现误用:编写最小化代码演示陷阱
  2. 验证可利用性:误用是否会造成真实漏洞?
  3. 检查文档:危险是否有文档说明?(文档不能弥补糟糕的设计,但会影响严重程度)
  4. 测试缓解措施:API能否通过合理努力安全使用?
如果发现有疑问,返回阶段2探查更多边缘情况。

References

严重程度分类

By category:
  • Cryptographic APIs: See references/crypto-apis.md
  • Configuration Patterns: See references/config-patterns.md
  • Authentication/Session: See references/auth-patterns.md
  • Real-World Case Studies: See references/case-studies.md (OpenSSL, GMP, etc.)
By language (general footguns, not crypto-specific):
LanguageGuide
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
See also references/language-specific.md for a combined quick reference.
严重程度标准示例
关键默认或明显用法不安全
verify: false
默认;允许空密码
容易的错误配置会破坏安全算法参数接受"none"
不常见但可能的错误配置负超时具有意外语义
需要故意误用模糊的参数组合

Quality Checklist

参考资料

Before concluding analysis:
  • Probed all zero/empty/null edge cases
  • Verified defaults are secure
  • Checked for algorithm/mode selection footguns
  • Tested type confusion between security concepts
  • Considered all three adversary types
  • Verified error paths don't bypass security
  • Checked configuration validation
  • Constructor params validated (not just defaulted) - see config-patterns.md
按类别:
  • 加密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
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 ",