数据库必须配置IP白名单而非仅依赖应用层,因云/容器环境IP动态变化;应使用环境变量和密钥管理服务管控连接参数;连接池需设超时与轻量验证语句;注意NAT/SLB导致的源IP变形,以日志实际IP为准配置。

数据库端必须配置白名单,不能只靠应用层“自觉”
应用服务器的 IP 不是固定不变的,尤其在容器或云环境里,192.168.0.100 今天是 A 服务,明天可能被回收分给 B 服务。只在应用代码里写死连接地址、不设数据库访问控制,等于把锁装在门外——门本身没锁。
实操建议:
- MySQL:在
mysql.user表中用HOST字段限制,例如创建用户时指定'app_user'@'10.20.30.40',**禁止用'%'通配符** - PostgreSQL:修改
pg_hba.conf,添加类似host all app_user 10.20.30.40/32 md5的行,改完必须pg_ctl reload或重启服务 - Oracle:没有原生 IP 白名单,需依赖网络层(如防火墙)或使用
SQLNET.ALLOWED_LOGON_VERSION_SERVER+ 网络 ACL 配合 - 注意:云数据库(如阿里云 RDS、AWS RDS)通常提供「安全组」或「白名单 IP 列表」控制台配置,优先走这个路径,比改内核配置更稳
连接字符串里别暴露密码,也别硬编码 IP
很多团队把 jdbc:mysql://10.20.30.40:3306/mydb?user=app&password=123456 直接塞进配置文件甚至代码里,这会让 IP 和凭证同时失控。IP 变了要改代码,密码泄露就直接崩盘。
实操建议:
- 用环境变量注入连接参数,例如
JDBC_URL=jdbc:mysql://${DB_HOST}:${DB_PORT}/mydb,再通过启动命令传入DB_HOST=10.20.30.40 - 密码绝不进 Git,用密钥管理服务(如 HashiCorp Vault、AWS Secrets Manager)或 K8s
Secret挂载 - 如果用 Spring Boot,优先配
spring.datasource.hikari.jdbc-url而非拆成 host/user/password 字段,减少拼接出错概率 - 检查日志是否意外打印完整
JDBC_URL—— 某些框架默认开启 debug 日志会吐出密码字段,需关闭或过滤
连接池超时与验证语句必须设,否则失效 IP 不会及时踢掉
应用连的是连接池,不是每次请求都新建 TCP 连接。如果数据库侧 IP 白名单变了(比如运维删了旧 IP),而连接池里的旧连接还活着,它们照样能继续查数据——你根本不知道防线已经漏了。
实操建议:
- HikariCP 必配:
connection-timeout=3000(避免卡死)、validation-timeout=3000、connection-test-query=SELECT 1(MySQL)或isValid(1)(JDBC 4.1+ 推荐) - Druid 建议启用
testWhileIdle=true+timeBetweenEvictionRunsMillis=30000,定期探活 - 所有验证语句必须是轻量级的,禁用
SELECT NOW()这类带函数调用的,某些数据库权限模型下它可能被拒绝执行 - 测试方法:手动从数据库白名单里删掉应用服务器 IP,观察应用是否在 1–2 分钟内报出
Access denied for user或Connection refused,而不是静默失败或卡住
别忽略 NAT 和负载均衡带来的 IP “变形”
应用服务器前面有 SLB、Nginx、K8s Service 或云厂商的 ALB?那数据库看到的 REMOTE_ADDR 很可能不是真实应用服务器 IP,而是中间设备的出口 IP。这时候按应用机器 IP 配白名单,永远连不上。
实操建议:
- 先确认数据库日志里实际记录的连接来源 IP 是什么:MySQL 查
general_log,PostgreSQL 看log_connections = on输出 - 如果用了 SNAT 或 Full-NAT 模式(如阿里云经典网络 SLB),只能把 SLB 的后端网段加进白名单,或改用支持 PROXY protocol 的方案(如 MySQL 8.0+ + HAProxy)
- K8s 场景下,Service 类型为
ClusterIP时,数据库看到的是 Node IP;类型为LoadBalancer或ExternalIP时,看到的是外部入口 IP —— 必须按实际观测到的 IP 配,不能想当然 - 临时排障可以用
tcpdump -i any port 3306在数据库机器抓包,看 SYN 包的源 IP 到底是谁
真正卡住人的从来不是“怎么加白名单”,而是 IP 在哪一层被替换、连接池缓存了多久、验证逻辑有没有真跑起来。多看一眼数据库日志里的实际连接来源,比翻十遍文档管用。

















