SCRAM 认证协议详解:SASL 盐值挑战响应机制

协议详解 · 2026-10-04

定义与历史背景

SCRAM(Salted Challenge Response Authentication Mechanism)是一种基于挑战-响应的密码认证协议,设计用于替代明文传输密码的传统认证方式。该协议由 IETF KITTEN 工作组标准化,核心规范为:

  • RFC 5802(2010):定义 SCRAM-SHA-1 基础机制
  • RFC 7667(2015):扩展支持 SCRAM-SHA-256 和通道绑定
  • RFC 7668(2015):定义 RFC 7667 的 TLS 扩展
SCRAM 解决了传统 SASL 认证中密码在网络中明文传输的安全隐患。与简单的哈希密码存储不同,SCRAM 引入盐和迭代计数,使暴力破解成本显著提高。

算法原理

核心公式

SCRAM 使用以下密码学原语:

$$H(password) = HMAC-SHA(N, password)$$

其中:

  • $N$ = 归一化后的用户名
  • $H$ = HMAC 函数(基于 SHA-1 或 SHA-256)
  • $i$ = 迭代计数(建议 ≥ 4096)
服务器端存储: $$StoredKey = H(ClientKey)$$ $$ServerKey = HMAC(Hi(password, salt, i), ServerPasswordVector)$$

客户端计算: $$ClientKey = HMAC(Hi(password, salt, i), "client key")$$ $$Signature = HMAC(ServerKey, message)$$

认证流程

第一步:客户端 → 服务器

CODE
c-first = n,rs=base64(salt),i=iteration-count
  • $n$:用户名(归一化)
  • $rs$:服务器生成的随机盐值
  • $i$:迭代次数
第二步:服务器 → 客户端
CODE
s-first = r=challenge, e=error
  • $r$:服务器随机挑战(用于构建通道绑定)
  • $e$:错误信息(如存在)
第三步:客户端 → 服务器
CODE
c-final = c=channel-binding, r=nonce, p=client-proof
  • $p$:客户端证明 = HMAC(ClientKey, auth-message)
  • $auth-message$ = c-firstᵢ, s-first, c-finalᵢ
第四步:服务器 → 客户端
CODE
s-final = v=server-proof, e=error
  • $v$:服务器验证 = HMAC(ServerKey, auth-message)

通道绑定(Channel Binding)

SCRAM-SHA-256-PLUS 变体要求通道绑定,防止中间人攻击:

绑定类型gs2-cbind-flag适用场景
无绑定n无安全通道环境
TLS 绑定pTLS 1.3+ session-hash 扩展
PFS 绑定y不支持通道绑定时使用
关键要求:如果服务器要求通道绑定,客户端 MUST 使用 -PLUS 后缀机制。

安全分析

威胁模型

SCRAM 设计应对以下攻击:

  • 网络窃听:密码不以明文传输,仅传输 HMAC 值
  • 暴力破解:盐和迭代计数显著提高离线攻击成本
  • 重放攻击:每次认证使用不同的随机挑战 $r$
  • 中间人攻击:通过通道绑定验证 TLS 会话完整性

已知漏洞与修复

RFC 7627 发现(2015): TLS 1.2 的 tls-unique 绑定存在中间人攻击风险。修复方案:

  • 使用 TLS 1.3 的 session-hash 扩展
  • 或在应用层验证证书指纹
迭代计数建议:
  • SHA-1 最低 4096 次
  • SHA-256 建议 4096~15000 次
  • 移动端设备需权衡安全与性能

与国密算法的对比

SCRAM 协议可与国密 SM3 结合使用:

特性SCRAM-SHA-256国密适配方案
哈希函数SHA-256SM3
HMAC 变体HMAC-SHA-256HMAC-SM3
OID1.3.6.1.5.5.18待 IANA 分配
应用场景PostgreSQL/MongoDB国密改造场景
注意:国密 SCRAM 尚无 RFC 标准,实际部署需参考 GM/T 0024-2023 或自行定义规范。

实际应用

PostgreSQL 配置示例

SQL
-- 查看支持的认证方式
SELECT * FROM pg_authid WHERE usename = 'admin';

-- 修改 scram-sha-256 认证
ALTER ROLE admin PASSWORD 'secure_password';

pg_hba.conf:

CODE
host    all    all    127.0.0.1/32    scram-sha-256
host    all    all    ::1/128         scram-sha-256

MongoDB 连接示例

JAVASCRIPT
const uri = 'mongodb://user:pass@host:27017/db?authMechanism=SCRAM-SHA-256';
const client = new MongoClient(uri);

Nginx 反向代理配置

NGINX
location /api/ {
    auth_request /auth;
}

location = /auth {
    internal;
    proxy_pass http://backend/auth-check;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Original-URI $request_uri;
}

后端认证服务验证 SCRAM 响应后返回 200/401。

与其他认证协议的对比

协议安全性性能开销兼容性
SCRAM-SHA-1中等低广泛
SCRAM-SHA-256高中等较好
Kerberos极高高企业级
LDAP Simple低低遗留系统
OAuth 2.0高中等Web/API
选型建议:
  • 数据库连接:优先 SCRAM-SHA-256
  • 企业统一认证:Kerberos 或 OAuth 2.0
  • 国密场景:待 GM/T 标准完善后评估

相关实践

参考