技术探讨:使用 stunnel 加密转发数据库连接时,如何获取客户端真实 IP?
在企业级架构设计中,数据安全与合规审计是重中之重。为了保障数据在传输过程中的安全性,防止内网嗅探,很多团队会选择使用 stunnel 等工具对数据库连接进行 SSL/TLS 加密转发。
然而,在实际落地过程中,许多开发者会遇到一个棘手的问题:经过 stunnel 转发后,数据库端(或数据库审计系统)无法获取到客户端的真实 IP 地址,只能看到 stunnel 代理服务器的 IP。
本文将深入剖析这一现象的技术原理,澄清常见的配置误区,并提供企业级场景下的标准解决方案。
一、 为什么 stunnel 无法透传真实 IP?
要理解这个问题,首先需要明白 stunnel 作为 TCP 代理的工作原理。
stunnel 本质上是一个基于 TCP 的加密代理网关。当客户端通过 stunnel 访问数据库时,实际上建立了两段完全独立的 TCP 连接:
- 第一段(客户端 -> stunnel 服务端):客户端与 stunnel 建立加密的 TLS 连接。此时,stunnel 看到的是客户端的真实 IP。
- 第二段(stunnel 服务端 -> 数据库) :stunnel 解密数据后,以自己的身份向数据库发起新的明文 TCP 连接。
由于 TCP 连接在 stunnel 处被"截断"并重新建立,对于后端的数据库而言,与它直接建立物理连接的源端就是 stunnel 服务器。因此,数据库底层 Socket 获取到的源 IP 地址,自然只能是 stunnel 的 IP 地址。
二、 常见误区:为什么 PROXY Protocol 在 stunnel 中不生效?
在 Web 开发中,我们通常通过 HTTP Header(如 X-Forwarded-For)来传递真实 IP。但在数据库协议(如 MySQL、PostgreSQL)中,并没有应用层的 Header 机制。
为了解决 TCP 层的真实 IP 透传问题,HAProxy 提出了 PROXY Protocol 标准。目前,主流数据库(如 MySQL 5.7+、PostgreSQL)均已原生支持该协议。
很多开发者会尝试在 stunnel 中配置 protocol = proxy,期望借此将真实 IP 传递给数据库,但这注定会失败。
原因解析:
stunnel 配置中的 protocol = proxy 选项,其作用是让 stunnel 作为服务端 去解析 客户端发来的 PROXY protocol 报文(即 stunnel 可以接收并理解真实 IP)。
但是,stunnel 原生并不支持作为客户端向后端发送 PROXY protocol 报文 。它没有类似 HAProxy 中 send-proxy 的功能。因此,即使你的数据库完美支持 PROXY Protocol,stunnel 也无法将解析到的真实 IP 传递给数据库。
三、 企业级场景下的解决方案
如果企业的合规审计、安全白名单或业务逻辑强依赖客户端的真实 IP,我们需要从架构或应用层面进行调整。以下提供三种主流解决方案:
方案一:架构升级,使用支持 PROXY Protocol 的代理(推荐)
如果必须从网络底层透传真实 IP,建议放弃使用 stunnel 进行数据库转发,改用支持双向 PROXY Protocol 的反向代理或负载均衡组件。
- HAProxy :作为业界标准的负载均衡器,HAProxy 完美支持该特性。
- 在 HAProxy 后端配置中添加
send-proxy-v2。 - 在数据库端开启 PROXY Protocol 支持(例如 MySQL 的
--proxy-protocol-networks参数)。
- 在 HAProxy 后端配置中添加
- Nginx (Stream 模块) :在 Nginx 的
stream块中配置proxy_protocol,配合后端的数据库支持,同样可以实现透传。 - 云原生负载均衡:如果业务部署在云端,可以直接使用云厂商提供的 TCP/SSL 负载均衡(如阿里云 SLB、腾讯云 CLB),它们通常原生支持透传真实 IP 或 PROXY Protocol。
优点:标准做法,对业务代码零侵入,数据库审计系统可直接获取真实 IP。
方案二:应用层改造,在业务代码中记录(最灵活)
如果网络架构无法更改,或者不想引入新的代理组件,可以将获取真实 IP 的逻辑上移到应用层。
- 实现方式 :在应用程序代码中(如 Java/Python/Go 的 Web 框架中),通过
request.getRemoteAddr()或类似方法获取当前发起请求的客户端真实 IP。然后,在执行业务 SQL 时,将该 IP 作为参数传递给数据库。 - 落地场景 :
- 在业务表中增加
client_ip字段,记录操作来源。 - 在应用层拦截器中,将真实 IP 写入独立的审计日志表或推送到日志中心(如 ELK)。
- 在业务表中增加
优点:无需修改网络基础设施,完全绕过底层 TCP 代理的限制,且业务逻辑可控。
方案三:网络层透明代理(极其复杂,仅限特殊场景)
在 Linux 环境下,可以通过 iptables 的 TPROXY 模块配合 stunnel 的透明代理模式(transparent = yes)来尝试保留源 IP。
- 实现方式:需要修改内核路由表,将数据库返回的流量通过策略路由牵引回 stunnel,从而让 stunnel 能够以客户端的真实 IP 和端口与数据库通信。
- 缺点:配置极其复杂,需要深厚的 Linux 网络内核功底;且数据库端必须能够处理这种非标准的透明连接,兼容性和稳定性较差。
建议 :此方案通常仅用于特殊的网络审计设备或运营商级别的 NAT 穿透,强烈不建议在常规的企业业务数据库架构中使用。
四、 总结与选型建议
在企业内网安全通信和数据库加密传输的场景中,stunnel 是一款优秀的轻量级加密工具,但它的定位是纯粹的 TCP 加密代理,而非具备高级流量调度能力的负载均衡器。
- 如果你的核心诉求是简单、快速地实现数据库连接加密 ,且不依赖 数据库端的真实 IP 审计,
stunnel完全胜任。 - 如果你的核心诉求是必须获取客户端真实 IP 以满足严格的合规审计要求,请果断采用 方案一(HAProxy/Nginx + PROXY Protocol) 或 方案二(应用层代码记录)。
技术选型没有绝对的好坏,只有是否契合业务场景。理解底层协议的原理,才能在设计企业级架构时避开陷阱,做出最合理的决策。