SCRAM-SHA-256

SCRAM-SHA-256(Salted Challenge Response Authentication Mechanism)是 PostgreSQL 10+ 默认推荐的密码认证方式,本质是基于挑战-响应(challenge-response)的 SASL 认证协议。它不会在网络上传输明文密码,也不会传输可以直接重放的密码哈希。

结合 PostgreSQL 协议来看,完整流程如下。


1. 用户密码保存阶段(服务器侧)

用户执行如下命令设置密码:

复制代码
ALTER USER test PASSWORD 'mypassword';

如果服务器配置了:

复制代码
password_encryption = scram-sha-256

那么服务器不会保存明文密码,而是保存类似下面的验证器(verifier):

复制代码
SCRAM-SHA-256$4096:<salt>$<StoredKey>:<ServerKey>

其中:

  • salt:随机盐
  • 4096:迭代次数(默认)
  • StoredKey
  • ServerKey

生成过程:

复制代码
SaltedPassword = Hi(password, salt, iterations)
ClientKey = HMAC(SaltedPassword, "Client Key")
StoredKey = SHA256(ClientKey)
ServerKey = HMAC(SaltedPassword, "Server Key")

服务器保存:

复制代码
salt
iteration count
StoredKey
ServerKey

不保存:

复制代码
明文密码
SaltedPassword

2. TCP连接建立

客户端连接 PostgreSQL:

复制代码
client                         server
  |                              |
  |---- StartupMessage --------> |
  |     user=test                |
  |     database=db              |
  |                              |

StartupMessage里面包含:

复制代码
user=test
database=db

3. Server 发起 SCRAM 请求

服务器发现:

复制代码
pg_hba.conf:
host all all 0.0.0.0/0 scram-sha-256

返回:

复制代码
AuthenticationSASL

内容:

复制代码
SCRAM-SHA-256
SCRAM-SHA-256-PLUS

表示支持哪些 SASL 机制。

协议:

复制代码
server
 |
 | AuthenticationSASL
 |
client

4. Client First Message

客户端选择:

复制代码
SCRAM-SHA-256

发送:

复制代码
client-first-message

例如:

复制代码
n,,n=test,r=fyko+d2lbbFgONRv9qkxdawL

含义:

字段 含义
n 不使用channel binding
n=test 用户名
r=xxx 客户端随机nonce

nonce是随机数。


5. Server First Message

服务器收到后:

  1. 根据用户名查找:

    pg_authid

找到:

复制代码
salt
iteration
StoredKey
ServerKey
  1. 生成自己的nonce

把:

复制代码
client nonce
+
server nonce

拼接。

返回:

复制代码
server-first-message

例如:

复制代码
r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvW,
s=QSXCR+Q6sek8bf92,
i=4096

字段:

字段 含义
r 完整nonce
s salt
i 迭代次数

6. Client计算Proof

客户端现在知道:

复制代码
password
salt
iteration
server nonce

计算:

第一步

计算:

复制代码
SaltedPassword

例如:

复制代码
Hi(
 password,
 salt,
 4096
)

第二步

计算:

复制代码
ClientKey
ClientKey =
HMAC(
SaltedPassword,
"Client Key"
)

第三步

计算:

复制代码
StoredKey
StoredKey =
SHA256(ClientKey)

第四步

生成认证消息:

复制代码
AuthMessage =
client-first-message
+
server-first-message
+
client-final-message-without-proof

第五步

计算:

复制代码
ClientSignature =
HMAC(
 StoredKey,
 AuthMessage
)

第六步

计算:

复制代码
ClientProof =
ClientKey XOR ClientSignature

发送:

复制代码
client-final-message

例如:

复制代码
c=biws,
r=xxx,
p=v0X8v3Bz...

其中:

复制代码
p = ClientProof

7. Server验证

服务器收到:

复制代码
ClientProof

自己计算:

复制代码
ClientSignature =
HMAC(
 StoredKey,
 AuthMessage
)

然后:

复制代码
ClientKey =
ClientProof XOR ClientSignature

得到:

复制代码
ClientKey

再计算:

复制代码
SHA256(ClientKey)

比较:

复制代码
SHA256(ClientKey)
==
StoredKey

如果一致:

认证成功。


8. Server返回最终证明

服务器发送:

复制代码
server-final-message

例如:

复制代码
v=rmF9pqV8S7suAoZWja4dJRkFsKQ=

这里:

复制代码
v = ServerSignature

客户端验证:

复制代码
ServerSignature =
HMAC(ServerKey, AuthMessage)

确认服务器是真的。


9. 最后 AuthenticationOk

服务器:

复制代码
AuthenticationOk

连接建立。


整个交互图

复制代码
Client                         Server
  |                              |
  | StartupMessage               |
  |----------------------------->|
  |                              |
  | AuthenticationSASL           |
  |<-----------------------------|
  |                              |
  | client-first-message         |
  |----------------------------->|
  |                              |
  | server-first-message         |
  |<-----------------------------|
  |                              |
  | client-final-message         |
  |  (ClientProof)               |
  |----------------------------->|
  |                              |
  | server-final-message         |
  |<-----------------------------|
  |                              |
  | AuthenticationOk             |
  |<-----------------------------|

和 MD5 认证区别

MD5 SCRAM-SHA-256
密码保存 md5(password+user) salt+StoredKey+ServerKey
网络传输 md5 response proof
防重放 一般
服务器是否知道密码
支持双向验证
支持channel binding

结合你之前分析 PostgreSQL/openGauss startup packet、Proxy认证、compute连接流程,SCRAM最关键的一点是:

Proxy如果伪装 PostgreSQL Server,需要完整实现 SCRAM 状态机,不能只转发用户名密码。

因为客户端发给 Proxy 的不是密码,而是:

复制代码
client-first-message
client-final-message(ClientProof)

Proxy必须:

  1. 保存用户SCRAM verifier(或转发到真正认证端)
  2. 生成server nonce
  3. 返回server-first-message
  4. 验证client proof

这也是 Neon Proxy / PostgreSQL兼容代理实现认证时比较复杂的地方。

相关推荐
Rabitebla41 分钟前
【Linux 系统编程】权限(一):身份、提权,和那 9 个权限位
linux·数据结构·c++·算法
BJ_Bonree1 小时前
博睿数据加入ITSS分会,成为国家级信息技术服务标准化体系单位成员!
大数据·运维·数据库·人工智能·可观测性
-dzk-1 小时前
【回溯】LC 22.括号生成
算法·回溯
杜 硕2 小时前
顺序表算法
数据结构·算法
AgentMaster3 小时前
智能客服多渠道接入,5 款产品的全渠道整合能力对比与实战
大数据·人工智能·算法
自传.3 小时前
B 站更新|软考架构师案例篇・数据库篇第 1-2 集上线|数据库规范化|索引视图物化视图真题精讲
数据库·软考高级·系统架构师·索引·案例分析·2026软考·软考系统架构师
jnrjian3 小时前
Oracle 没有drop any job 只需要create any job Session_Privs
数据库
sali-tec4 小时前
C# 基于OpenCv的视觉工作流-章108-区域筛选
图像处理·人工智能·opencv·算法·计算机视觉