Ctrl-C in psql gives me the heebie-jeebies
摘要
深度分析PostgreSQL查询取消机制的安全漏洞,揭示psql中Ctrl-C处理的历史性安全隐患。
核心发现
- 取消请求明文发送:即使主连接使用最严格的TLS设置,CancelRequest始终明文发送
- Postgres 17才支持加密:直到2025年才在libpq中添加加密CancelRequest的功能
- psql仍未使用加密:需要大型重构才能调用非信号安全的加密函数
- 协议v3.2支持长密钥:secret key可长达256字节,但默认不使用
- DoS攻击风险:窃听者可重放取消请求进行拒绝服务攻击
CancelRequest机制原理
要取消Postgres查询,Postgres客户端通过新的额外连接连接到服务器,形式为CancelRequest。服务器通过启动消息开头的魔数协议版本号区分普通客户端连接:
最新Postgres协议是v3.2 (0x00030002)
CancelRequest声称是v1234.5678 (0x04d2162e)
CancelRequest针对连接而非特定查询。目标连接由服务器在连接握手结束时最初提供给客户端的两个数字标识(通过BackendKeyData消息):
- 4字节进程ID (process ID)
- 4字节随机密钥 (secret key)
除消息长度初始值外,客户端只发送这些。没有凭据要求,除了那个4字节密钥。
安全漏洞详解
1. 明文发送的取消请求
psql始终发送明文CancelRequest。即使连接携带查询使用最严格的TLS设置(sslmode=verify-full, channel_binding=require),psql仍然以明文方式取消。
2. psql仍未使用加密函数
Postgres 17之后,许多基于libpq的驱动(如ruby-pg)现在使用新的加密函数。但psql本身仍然不使用它们。
Postgres开发者并非不知道这个问题。存在架构原因导致psql尚未使用libpq的加密取消函数(需要大型重构以调用非信号安全的新函数)。但针对未来某些版本的补丁正在开发中。
3. 暴力破解密钥风险
4字节密钥可能被暴力破解的风险导致二十多年来第一次Postgres协议更新。协议v3.2与v3.0的唯一区别是取消的密钥可以长达256字节。
但libpq和psql仍然不使用这个新版本,除非你在连接字符串末尾明确指定min_protocol_version=3.2。
4. 重放攻击风险
使用最新psql并指定protocol 3.2获得无法暴力破解的密钥后,一旦你取消查询,任何能看到你网络流量的人(如同一开放WiFi网络上的任何人)可以对你的同一连接发起拒绝服务攻击,只需反复重放拦截的取消请求。
Elephantshark案例
作者创建并维护Elephantshark,一个开源Postgres网络流量监控工具,类似Wireshark但专门用于Postgres,作为代理实现。
CancelRequest未加密导致了实际问题:当通过Elephantshark连接Postgres over TLS时,Elephantshark通常使用TLS的SNI (Server Name Indication) 扩展加上可自定义后缀来确定目标服务器。
例如:监控到ep-adj-noun-abc1234.region.aws.neon.tech的连接,运行elephantshark然后连接到ep-adj-noun-abc1234.region.aws.neon.tech.local.neon.build。任何.local.neon.build子域名解析到127.0.0.1,Elephantshark就在那里运行。
但当你按下查询的"刹车"时,你的CancelRequest以明文发送,没有SNI,意味着没有目标主机的记录。Elephantshark需要识别何时被要求从和到localhost转发,这会导致无限循环。
解决方案:接收普通客户端连接时,更新将(process ID, secret key)值映射到目标主机的数据结构。随后收到没有SNI的CancelRequest时,使用它指定的(process ID, secret key)查找目标主机。
安全建议
如果你非常关心安全,请执行以下部分或全部操作:
- 使用Postgres 18和min_protocol_version=3.2
- 使用VPN
- 不要在psql中使用Ctrl-C
- 检查你使用的任何其他Postgres客户端或驱动是否在加密它们的CancelRequest
Elephantshark可以帮助检查最后一点。作者计划在未来使这类检查更容易。
核心洞察
"Anyone who can see your network traffic (e.g. anyone on the same open WiFi network) can mount a Denial of Service attack. Specifically, they can cancel any and all future queries on the same connection, just by repeatedly replaying the intercepted cancellation request."
这揭示了一个历史悠久但被忽视的安全隐患。在网络安全日益重要的今天,这个"不起眼"的细节可能成为攻击向量。