Ctrl-C in psql gives me the heebie-jeebies
摘要
Postgres查询取消机制存在严重安全隐患:Ctrl+C发送的CancelRequest以明文传输,即使主连接已启用TLS加密。这可能导致DoS攻击和数据安全风险。
核心发现
⚠️ 安全隐患:psql中的Ctrl+C取消请求始终以明文传输,即使主连接使用最严格的TLS设置(sslmode=verify-full, channel_binding=require)
工作原理
取消Postgres查询时,客户端会创建一个新的单独连接到服务器,即CancelRequest。服务器通过启动消息中的魔数协议版本号来区分普通连接:当前最新协议是v3.2,但CancelRequest声称使用v1234.5678。
CancelRequest通过两个数字标识目标连接:服务器在连接握手结束时提供的4字节进程ID和4字节随机密钥。
安全问题
- 明文传输:即使主连接使用TLS,CancelRequest始终以明文发送(Postgres 17之前完全不支持加密,之后libpq支持但psql未使用)
- 竞态条件:按连接而非按查询取消,可能取消错误的查询
- 暴力破解:4字节密钥可被暴力破解,Postgres 18已支持256字节密钥
- DoS攻击:任何人可以重放拦截的取消请求,对同一连接执行DoS攻击
💡 关键洞察:"在开放WiFi网络上,任何人都可以重放拦截的取消请求来取消所有未来查询"
技术细节
Postgres 17在libpq中添加了发送加密CancelRequest的函数,但psql本身仍未使用它们。由于"新函数不是信号安全的,需要更大重构"——针对未来版本的补丁正在开发中。
Postgres 18是20多年来首次协议更新,v3.2与v3.0的唯一区别是可以使用最长256字节的取消密钥。但libpq和psql仍默认不使用此新版本,除非在连接字符串中明确指定min_protocol_version=3.2。
相关项目
作者还创建了Elephantshark,一个开源的Postgres网络流量监控工具,类似于专门针对Postgres的Wireshark。
影响与建议
这一发现对Postgres生态的开发者有重要影响。建议:
- 在连接字符串中指定min_protocol_version=3.2
- 关注psql未来更新
- 在使用公共网络时特别注意