暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

你还在用 password 认证方式?PostgreSQL 安全认证的“隐形杀手”

安呀智数据坊 2026-03-20
122

注:本文为安丫科技·刘峰原创。 转载请注明出处,严禁抄袭。

⚠️ 风险提示:文中代码仅供测试环境学习。生产环境复杂,严禁盲目套用,后果自负。如遇紧急故障或需兜底支持,请联系安丫专家团队。

一个 PostgreSQL SQL 查询,明明没有改动代码、索引也没有问题,却突然从 毫秒级变成了分钟级的执行时间?

经过一番排查,竟然发现:优化器做出的执行计划 极为低效,看起来“像是盲猜”一样。

最令你困惑的,往往是:SQL 没有变化,为什么优化器的选择变得不靠谱了?

在这篇文章中,我将带你 深入剖析,为什么 PostgreSQL 的 password 认证方式,实际上是一个 “隐形的安全杀手”,而 md5 和 scram 认证可以提供更强的防护。


01

 理论篇:三种认证方式的底层

 原理解析

这三种认证方式的核心差异,在于密码在网络通信中是如何传输的,以及如何对抗网络嗅探(Sniffing)、重放攻击(Replay Attack)和拖库攻击。


1

 password 认证:在互联网上“裸奔”  

工作原理


当客户端尝试连接数据库时,服务端要求输入密码。

客户端接收到用户输入的密码后,不加任何处理,直接以纯明文的形式(Plaintext)封装在 TCP 数据包中发给服务端。


安全致命点


任何位于同一局域网、路由器节点或通信链路上的攻击者,只要使用网络抓包工具(如 tcpdump、Wireshark),就能像看普通文本一样直接读取你的数据库密码。


2

md5 认证:经典的“挑战-响应”机制

为了解决明文传输的问题,PostgreSQL 引入了基于 MD5 的挑战-响应(Challenge-Response)机制。

工作原理


a) 挑战

客户端发起连接,服务端随机生成一个 4字节的盐(Salt) 发给客户端。

b)计算

客户端使用用户输入的密码、用户名以及服务端发来的盐,进行双重哈希计算:Hash = MD5( MD5(password + username) + salt )。

c)响应

客户端将计算出的最终 Hash 值发给服务端,服务端用相同规则比对。


为什么安全


密码的明文从未在网络上出现过。

攻击者抓包只能看到服务端的“盐”和客户端的“Hash响应”。

由于每次连接“盐”都是随机变化的,攻击者即使截获了这次的 Hash 值,也无法在下次连接时用来重放登录。


3

scram-sha-256 认证:现代密码学的终极

 防线

虽然 MD5 能防网络嗅探,但 MD5 算法本身已不安全,且存在“哈希传递攻击(Pass-the-Hash)”的弱点(即:如果系统表 pg_authid 被盗,攻击者可以直接用里面存储的 MD5 值冒充客户端登录)。

因此,PG 10 引入了 SCRAM(Salted Challenge Response Authentication Mechanism,RFC 7677)。


工作原理


它是一种复杂的双向认证机制。

客户端和服务端会互相交换自己生成的随机数(Nonce),并通过 PBKDF2-SHA-256 算法进行成千上万次的迭代运算,最终生成复杂的 ClientProof(客户端证明)和 ServerSignature(服务端签名)


为什么最安全


  • 极强的防嗅探能力

    网络上传输的仅仅是基于随机数和迭代计算的动态证明。

  • 防伪造服务器

    不仅服务端验证客户端,客户端也能验证服务端(防止中间人伪造数据库节点)。

  • 防拖库传递

    即使数据库密码表泄露,攻击者也无法反推明文,更无法直接使用泄露的密文进行登录。


02

 实战篇:全流程 tcpdump 抓包与

 协议解析 

为了让理论落地,我们设计了以下完整的实验流程。

我们将通过 tcpdump 深入 PostgreSQL 的通讯协议层(Wire Protocol),亲眼见证数据包里的秘密。


1

实验环境准备 

我们需要开启两个终端窗口:终端 A 用于执行抓包,终端 B 用于模拟客户端登录。

  • 测试用户

    dbuser

  • 测试密码

    Secret@123

  • 抓包命令

    sudo tcpdump -i any -A -s 0 port 5432

  • -i any

    监听所有网卡接口。

  • -A

    核心参数,将数据包的 Payload 以 ASCII 明文形式打印,便于观察。

  • -s 0

    捕获完整的数据包,防止报文截断。


注意




为了确保抓包能看到认证协议,实验全程使用 PGSSLMODE=disable 环境变量强制关闭 SSL 链路加密,模拟纯明文通道下的认证过程。


2

实验 1:令人触目惊心的 password 抓包

Step 1: 修改配置并重载 


在数据库服务器上,编辑 pg_hba.conf,将 IPv4 本地连接的认证方式改为 password:

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             dbuser          0.0.0.0/0               passwor


执行重载命令生效:SELECT pg_reload_conf();


Step 2: 开启抓包


在 终端 A 执行:

sudo tcpdump -i any -A -s 0 port 5432


Step 3: 模拟客户端登录


在 终端 B 发起连接并输入密码 Secret@123:

PGSSLMODE=disable psql -U dbuser -h 127.0.0.1 -W


Step 4: 报文解析 


回到终端 A,你会看到长串的 TCP 交互。

我们在其中精准定位到客户端发送密码的数据包:

深度剖析


注意最后一行 ....p...Secret@123.。在 PostgreSQL 协议中:

  • 字母 p 代表这是一个 PasswordMessage。

  • 紧接着的 4 个字节代表消息长度。

  • 后面跟着的,就是毫无遮掩的纯明文密码 Secret@123,最后以 \0 结尾。

  • 结论

    在没有配置 SSL 的情况下使用 password 认证,任何能接触到网络流量的人都能瞬间盗取你的数据库最高权限。


3

实验 2:md5 是如何隐藏密码的?

Step 1: 修改配置与密码加密方式 


修改 pg_hba.conf 的 METHOD 为 md5 并重载配置。 

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             dbuser          0.0.0.0/0               md5


同时,我们需要确保数据库以 md5 格式存储该用户的密码(PostgreSQL 14+ 默认是 scram,需回退演示):

ALTER SYSTEM SET password_encryption = 'md5';
SELECT pg_reload_conf();
\password dbuser  -- 重新输入 Secret@123,使其以 md5 哈希存入系统表


Step 2: 开启抓包并登录 


保持终端 A 的 tcpdump 运行,终端 B 再次执行登录:

PGSSLMODE=disable psql -U dbuser -h 127.0.0.1 -W


Step 3: 报文解析 


这一次,我们在抓包结果中找到了两次关键交互(挑战与响应):

以下是一份真实的、原汁原味的 Linux 生产环境抓包日志。

我们将逐个数据包拆解 MD5 是如何隐藏密码的。


数据包 1:服务端发起 MD5 挑战(下发随机 Salt)

18:51:15.869475 IP localhost.postgres > localhost.61332: Flags [P.], seq 1:14, ack 81, win 128, options [nop,nop,TS val 159740625 ecr 159740623], length 13
E..A..@.@.f(.........8...R.o.s.......5.....
        .r.     .r.R........iJ..

分析


1)TCP 干扰项

开头的 .r. .r. 是底层 TCP 时间戳选项(TCP Timestamp Options)被强制转换为 ASCII 的结果,与数据库无关。

2)PG 协议载荷

真正的核心是最后的 R........iJ..(总长 13 字节)。

  • R

    代表消息类型为 AuthenticationRequest。

  • 紧接着不可见的 4 字节代表认证类型,值为 5(MD5 认证)。

  • iJ..

    这就是服务端这次随机生成的 4 字节盐(Salt)。


数据包 2:客户端发送 MD5 响应(Hash 值)

18:51:15.870407 IP localhost.61332 > localhost.postgres: Flags [P.], seq 81:122, ack 14, win 128, options [nop,nop,TS val 159740626 ecr 159740625], length 41
E..]')@.@..p...........8.s...R.|.....Q.....
        .r.     .r.p...(md585eba7f665f54bf44e628307c6d2c3f1.

逐字节拆解


这是 MD5 认证最核心的一步,PG 负载内容为 p...(md585eba7f665f54bf44e628307c6d2c3f1.:

1)p

代表消息类型 PasswordMessage。

2) ...(

表示消息长度。

有趣的是,括号 ( 在 ASCII 码表中的十进制正是 40。

加上开头的 p,总长度恰好是 41 字节。

3) md585eba7f66...

这是客户端使用公式 MD5(MD5(密码+用户名) + "iJ..") 计算出的响应值。




结论


我们在这个包里找不到任何明文密码

黑客即便截获了这一串 md585eba... 也无法反推密码,且因为下一次登录服务端会下发全新的 Salt,这个旧哈希值无法用于重放攻击。


数据包 3:认证成功与参数下发(意外的安全启示)

18:51:15.872288 IP localhost.postgres > localhost.61332: Flags [P.], seq 14:467, ack 122, win 128, options [nop,nop,TS val 159740628 ecr 159740626], length 453
E.....@.@.do.........8...R.|.s.............
        .r.     .r.R........S....in_hot_standby.off.S....integer_datetimes.on.S....TimeZone.Asia/Shanghai.S....IntervalStyle.postgres.S... search_path."$user"public.S....is_superuser.off.S....application_name.psql.S...&default_transaction_read_only.off.S....scram_iterations.4096.S....DateStyle.ISO, MDY.S...#standard_conforming_strings.on.S...!session_authorization.dbuser.S....client_encoding.UTF8.S....server_version.18.3.S....server_encoding.UTF8.K.......&.r..Z....I

逐字节拆解


你可能会对这段突然冒出的大量“明文”感到疑惑。

这恰恰证明了MD5 认证已经通过!

1) R........

这里的 R 代表 AuthenticationOk(认证成功)。

2)大段的 S....

代表 ParameterStatus。

服务端开始向客户端下发明文会话参数,如 TimeZone.Asia/Shanghai、server_version.18.3、client_encoding.UTF8 等。

3)最后的 Z....I

代表 ReadyForQuery,状态为 I(Idle)。

至此,连接建立完成,可以敲 SQL 了。


3

实验 3:scram-sha-256 的硬核交互过程

虽然 MD5 防住了抓包,但 MD5 算法本身容易被碰撞破解,且如果黑客拿到了数据库的 pg_authid 系统表,可以直接用里面的 MD5 值冒充客户端登录。

我们来看 SCRAM 是怎么解决的。


Step 1: 修改配置与密码加密方式 


修改 pg_hba.conf 的 METHOD 为 scram-sha-256 并重载。

# TYPE  DATABASE        USER            ADDRESS                 METHOD
host    all             dbuser          0.0.0.0/0               scram-sha-256


同时,将会话加密方式切换为 scram 并重置密码:

ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
\password dbuser  -- 重新输入 Secret@123,以高强度 SCRAM 格式存储


Step 2: 开启抓包并登录 


执行抓包和 psql 登录命令。

PGSSLMODE=disable psql -U dbuser -h 127.0.0.1 -W、

Step 3: 报文解析


SCRAM 的认证过程基于 SASL(简单认证与安全层)框架,交互极度复杂,我们在 tcpdump 中会看到三次握手级的认证报文:


报文 1:Client First Message (客户端发起 SASL 认证,包含客户端生成的随机数 Nonce)

18:54:07.123827 IP localhost.13366 > localhost.postgres: Flags [P.], seq 81:136, ack 25, win 128, options [nop,nop,TS val 159911880 ecr 159911879], length 55
E..k..@.@.".........46.8 h....K......_.....
        ...     ...p...6SCRAM-SHA-256.... n,,n=,r=3ewP3o9XZ8s/WTY4RXKJKxNY


报文 2:Server First Message (服务端返回自己的随机数、Salt、以及 PBKDF2 迭代次数)

18:54:07.123967 IP localhost.postgres > localhost.13366: Flags [P.], seq 25:118, ack 136, win 128, options [nop,nop,TS val 159911880 ecr 159911880], length 93
E...2!@.@.
D.........846..K. h.............
        ...     ...R...\....r=3ewP3o9XZ8s/WTY4RXKJKxNYaR5rBiV4x/WhGbfOU81L1qjY,s=aYJIjMymmcu7HyWPrtzJUg==,i=4096

深度剖析


可以看到服务端带回了 s= (Base64编码的盐) 和 i=4096 (告诉客户端:你需要把密码进行 4096 次 SHA-256 迭代计算!),以此极大增加暴力破解的算力成本。


报文 3:Client Final Message (客户端发送复杂的计算证明)

18:54:07.129549 IP localhost.13366 > localhost.postgres: Flags [P.], seq 136:245, ack 118, win 128, options [nop,nop,TS val 159911885 ecr 159911880], length 109
E.....@.@."k........46.8 h....K{...........
        ...     ...p...lc=biws,r=3ewP3o9XZ8s/WTY4RXKJKxNYaR5rBiV4x/WhGbfOU81L1qjY,p=c10/1yrKOH3VPAfYzTJ5IG069ZTxVBx+kglex3qsNGY=

深度剖析


客户端最终发回的 p= 是 ClientProof。它是通过 ClientKey 和 ServerSignature 进行异或运算得出的。

这个证明不仅向服务端证实了“我知道密码”,同时也验证了“当前连接的服务端是真的”,防住了中间人攻击。




结论


全程没有密码影子,黑客即便抓包拿到了所有随机数和 Proof,面对 SHA-256 和 4096 次迭代,也根本无法逆向出密码。


03

结论

通过上述完整的环境配置、tcpdump 的 -A 抓包实验以及协议层解析,我们用实打实的数据包证明了结论:

避坑指南


即便你使用了 scram-sha-256,它保护的也仅仅是认证阶段的密码安全。

一旦认证通过,你执行的 SQL 语句和业务数据依然是明文传输的(如前文 tcpdump 演示,SQL 语句也会被一览无余)。 

因此,在生产环境中,配置 SCRAM-SHA-256 认证 + 强制开启 SSL/TLS 加密(将 pg_hba.conf 中的 host 改为 hostssl),才是保障数据库链路安全的终极黄金法则。


写在最后


你在生产环境中是否曾遇到过认证安全问题?

你使用的是哪种认证方式?

是否曾经因认证漏洞造成性能或安全隐患?

欢迎在评论区分享你的经验,探讨更多 PostgreSQL 安全防护 的最佳实践!

作者介绍

大家好,我是刘峰,安丫科技创始人 & 数据库技术高级讲师,专注于 PostgreSQL、国产数据库运维与迁移、数据库性能优化 等方向。

作为 PG中国分会官方授权讲师、PostgreSQL ACE 讲师认证专家,我长期活跃在一线项目实战中,拥有 10年以上大型数据库管理与优化经验,曾深度参与电信、金融、政务等多个行业的数据库性能调优与迁移项目。

欢迎关注我,一起深入探索数据库的无限可能,技术交流不设限!

📌 觉得有收获的话,记得点赞、收藏、转发支持一下哦,别忘了关注我获取更多数据库干货~

安呀智数据坊|我们能做什么

无论你是业务系统的技术负责人,还是数据部门的第一响应人,我们都能为你提供可靠的支持:

  • 数据库类型支持

    Oracle MySQL / PostgreSQL / SQL Server 等主流数据库

  • 核心服务内容

    性能优化 / 故障处理 / 数据迁移 / 备份恢复 / 版本升级 / 补丁管理

  • 系统性支持

    深度巡检 / 高可用架构设计 / 应用层兼容评估 / 运维工具集成

  • 专项能力补充

    定制课程培训 / 甲方团队辅导 / 复杂问题协作排查 / 紧急救援支持

📮 如果你有一张删不掉的表、一个跑不动的查询,或者一场说不清的升级风险,欢迎来找我们聊聊。

END

关键词回复(可见相应文章):

oracle、mysql、pg、postgresql、sql、性能优化、故障处理、数据迁移、备份恢复、版本升级、补丁管理、深度巡检、解决方案、架构设计......

添加微信好友1对1咨询

\ | /

动动你的手指

【安呀智数据坊】加个星标吧~

这样你就不会丢下我啦~

记得加星标呀!

文章转载自安呀智数据坊,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论