3. 网络层安全加固

Redis 默认监听所有网络接口(0.0.0.0),且早期版本默认无认证。一旦端口 6379 暴露到公网,攻击者可直接写入 SSH 公钥、计划任务或主从复制恶意载荷,实现远程命令执行。网络层加固的目标不是"加一层密码",而是把 Redis 的可达范围从"任何能路由到它的主机"收缩到"仅业务进程所在的可信主机与端口"。本节围绕四个控制点展开:bind 决定监听哪些地址,protected-mode 决定无认证时的兜底拒绝,防火墙决定谁能到达该端口,TLS 决定链路上的数据是否可被窃听或篡改。

一、bind:把监听地址收敛到可信网卡

bind 指令控制 Redis 在哪些本地地址上接受连接。它不是白名单——写 bind 10.0.1.5 表示只在该网卡上监听,其他网卡(包括 127.0.0.1 之外的公网网卡)根本不建立监听套接字,连接请求在 TCP 层就被拒绝。这是最彻底的一层收敛。

常见配置形态与含义:

  • bind 127.0.0.1 -::1:仅本机可访问,适合单机应用与本地运维。
  • bind 127.0.0.1 10.0.1.5:本机 + 内网业务网卡,应用服务器通过 10.0.1.5 访问,公网网卡不监听。
  • bind 0.0.0.0:监听全部 IPv4 地址,仅在容器或严格受控网络中使用,且必须配合防火墙与认证。

需要注意两点。第一,Redis 6 之前 bind 后若写多个地址,任一地址不可用会导致启动失败;Redis 6+ 改为"尽力绑定",不可用的地址会跳过并记录日志,因此启动后必须核对实际监听结果。第二,修改 bind 后应通过 ss -lntp | grep 6379 或 redis-cli -h <ip> -p 6379 ping 验证:期望的地址返回 PONG,非期望地址应连接超时或被拒绝。

二、protected-mode:无认证时的兜底闸门

protected-mode yes(3.2 起默认开启)的判定逻辑是:当没有配置密码且没有显式 bind 到具体地址(即监听 0.0.0.0 或未配置 bind)时,Redis 只接受来自回环地址的连接,其他来源一律返回错误并拒绝执行命令。它是一道"配置疏忽保护",而不是访问控制手段。

因此存在一个常见误区:以为开了 protected-mode 就安全了。只要同时设置了 requirepass,protected-mode 就不再拦截外部连接——此时安全性完全依赖密码强度与网络边界。正确做法是:bind 收敛 + protected-mode 保持 yes + 认证三者叠加,而不是互相替代。若确需在容器内监听 0.0.0.0,应显式设置 protected-mode no 并同时用防火墙限制来源,且清楚这是有意为之的取舍。

三、防火墙:在主机与网络边界双重收口

bind 解决"本机监听哪些地址",防火墙解决"哪些远端主机能到达这些地址"。两者是不同层次,缺一不可。典型做法是主机防火墙(iptables/nftables/firewalld)只放行应用服务器网段,网络 ACL/安全组再限制一次。

# 仅允许 10.0.1.0/24 访问 6379,其余丢弃
iptables -A INPUT -p tcp --dport 6379 -s 10.0.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP

# firewalld 等价写法
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" port port="6379" protocol="tcp" accept'
firewall-cmd --reload

验证时不要只看规则是否存在,要实际从允许主机和禁止主机各发起一次连接:允许侧应能完成 PING,禁止侧应表现为超时(DROP)或拒绝(REJECT)。同时检查是否误放行了 0.0.0.0/0,以及云安全组与主机防火墙是否一致——只改一处是排障中最常见的"以为封了其实没封"。

四、TLS:让链路本身不可读、不可改

当 Redis 跨不可信网络(跨可用区、跨机房、混合云)通信时,仅靠 bind 和防火墙无法防止链路上的嗅探与中间人。Redis 6 起原生支持 TLS,需要准备 CA、服务端证书/私钥、客户端证书,并在配置中启用:

tls-port 6379
port 0                      # 关闭明文端口
tls-cert-file /etc/redis/tls/redis.crt
tls-key-file  /etc/redis/tls/redis.key
tls-ca-cert-file /etc/redis/tls/ca.crt
tls-auth-clients yes        # 要求客户端证书(双向认证)
tls-protocols "TLSv1.2 TLSv1.3"

客户端连接需带 TLS 参数:redis-cli --tls --cacert ca.crt -h redis.internal -p 6379 ping。若使用主从复制,replicaof 与 tls-replication yes 需一并配置,否则复制链路仍走明文。验证要点:明文端口应无法连接;不带客户端证书的连接应被拒绝;openssl s_client -connect redis.internal:6379 -CAfile ca.crt 能完成握手并显示证书链。

TLS 只保护传输层,不替代认证与命令权限控制。证书私钥权限应为 600 且属主为 redis 用户;证书过期会导致连接整体失败,需纳入监控。
Redis 网络暴露面收敛:四层控制点 公网 / 不可信主机 扫描 6379、尝试未授权 ③ 防火墙 / 安全组 仅放行 10.0.1.0/24 其余 DROP 可信应用服务器 10.0.1.21 持有客户端证书 Redis 主机 10.0.1.5 ① bind 127.0.0.1 10.0.1.5 ② protected-mode yes 被拦截 放行 TLS ④ TLS 加密通信(tls-port 6379,port 0) CA 签发证书 · 双向认证 tls-auth-clients yes · TLSv1.2/1.3 复制链路 tls-replication yes,避免主从明文泄露 期望结果 • 10.0.1.21 经 TLS 连接 → PONG • 公网主机连接 6379 → 超时 / 拒绝 • 无客户端证书 → 握手失败 • 明文端口 6379 → 无法建立连接 常见失效点 • 只改 bind 未改防火墙,安全组仍 0.0.0.0/0 • 设了 requirepass 后误以为 protected-mode 仍生效 • 主从复制未开 tls-replication,链路明文 • 证书过期导致全量连接失败

五、组合验证与配置基线

四个控制点应按"由内到外"的顺序验证:先确认监听地址正确,再确认无认证兜底生效,再确认远端可达性符合预期,最后确认链路加密与证书校验。下面给出一份可直接对照的检查表(示例参数,需按实际网段替换)。

控制点配置示例验证命令通过判据
bindbind 127.0.0.1 10.0.1.5ss -lntp | grep 6379仅出现 127.0.0.1 与 10.0.1.5
protected-modeprotected-mode yes无密码时从外部连接返回 DENIED 提示
防火墙仅放行 10.0.1.0/24从允许/禁止主机各连一次允许侧 PONG,禁止侧超时
TLStls-port 6379, port 0redis-cli --tls --cacert ...握手成功且明文端口不可连
加固顺序建议:先 bind 收敛,再确认 protected-mode,再补防火墙,最后上 TLS。每改一项立即验证,避免多项同时变更导致无法定位是哪一层拦截了连接。

最后强调一个工程习惯:把上述配置写入版本化的配置文件模板,并在变更后保留 CONFIG GET bind、CONFIG GET protected-mode、CONFIG GET tls-port 的输出作为证据。网络层加固的价值不在于"配了",而在于"能证明只有预期的主机能以预期的方式访问"。