Skip to content

Gateway API Key 的明文存储与非恒定时间比对

证据等级:F(源码直接证明)
分析基线:4f843556


一句话

Gateway API Key 验证优先使用明文比对,回退到 SHA256 哈希。两者均使用 Python == 而非恒定时间比较。SHA256 无盐。注释将安全回归标记为"progress"。


1. 验证路径:明文优先

backend/app/api/gateway.py:45-48

# First try plaintext (new behavior)
result = await db.execute(
    select(Agent).where(
        Agent.api_key_hash == api_key,    # ← 明文直接比对

验证先尝试明文匹配,失败后才回退到哈希。注释称明文为"new behavior"——即未来计划删除哈希回退,全部改为明文存储。


2. 非恒定时间比对

门关(gateway)使用 Python 的 == 操作符来比对 API Key:

Agent.api_key_hash == api_key

Python 的 == 在字符串比较时会在第一个不匹配字符处提前返回,比较时间与密钥前缀匹配长度成正比。攻击者可以通过计时攻击逐步猜测 key 的前缀。

对比:WhatsApp 和 Slack 的 webhook 验证使用 hmac.compare_digest——恒定时间比较。


3. 哈希无盐

hashlib.sha256(raw_key.encode()).hexdigest()

SHA256 无盐。如果迁移到明文存储完成,数据库泄露即全泄露。即使保留哈希,无盐意味着相同的 key 产生相同的哈希,攻击者可以批量比对。


4. 注释用词

# First try plaintext (new behavior)
# ... fallback to hashed (legacy)

注释将"明文存储"称为"new behavior"和"progress",将"哈希存储"称为"legacy"。这暗示项目的安全方向是从哈希到明文——与行业最佳实践相反。


5. 与 AI Coding 的关系

  1. 注释反映 prompt 意图:开发者(或 AI)被要求"添加明文比对作为新行为"——AI 忠实地执行了,并加上了注释标记状态
  2. 无安全意识:AI 不会主动说"明文存储 API Key 是安全风险,不应标记为 progress"——这需要安全判断
  3. 非恒定时间比对== 是 Python 中最自然的字符串比较方式——AI 不会主动选择 hmac.compare_digest,除非 prompt 明确要求
  4. WhatsApp/Slack 的 hmac.compare_digest 是另一个开发者/任务的结果——同一个安全属性在不同模块中实现不一致

6. 关联