Redis 安全加固是中间件防护中极易被忽视的一环:Redis 默认无认证、监听 0.0.0.0:6379,一旦暴露公网,攻击者可通过写入 crontab、SSH 公钥或主从复制加载恶意模块直接实现远程命令执行(RCE)。本文给出从检测到加固的完整配置方案。
适用场景
- 生产环境自建的 Redis 4.x – 7.x 单机或哨兵集群
- Docker / Kubernetes 中部署、端口映射到宿主机或公网的 Redis
- 安全扫描发现 6379 端口开放、需快速收敛风险的服务器
前置条件
- 服务器 root 或 sudo 权限,可修改 Redis 配置并重启服务
- 确认业务方依赖的 Redis 指令集(禁用命令前需与开发确认)
原理说明
Redis 未授权访问攻击链分四类:
- 写 crontab:利用
CONFIG SET dir/dbfilename把恶意任务写入/var/spool/cron,反弹 shell。 - 写 SSH 公钥:把
authorized_keys写入~/.ssh,实现免密登录。 - 主从复制 RCE:通过
SLAVEOF让目标 Redis 成为攻击者 Redis 的从库,加载恶意.so模块执行命令(影响 4.0 – 6.2 部分版本)。 - 数据窃取:直接
KEYS */GET拖走缓存与会话数据,引发数据泄露与账户接管。
攻击前提只有一个:6379 端口可达且无认证。因此加固核心是「网络隔离 + 强认证 + 禁用危险命令」三层。
操作步骤
1. 检测未授权访问
# 本机检测(模拟攻击者)
redis-cli -h 127.0.0.1 -p 6379 ping
# 返回 PONG 且无 AUTH 报错 → 存在未授权访问风险
# 远程检测(换用目标公网 IP,仅限授权测试)
nc -zv <target-ip> 6379
redis-cli -h <target-ip> -p 6379 info server | head -5
2. 绑定地址:禁止公网监听
# 编辑 /etc/redis/redis.conf(或 /etc/redis.conf)
# 仅监听回环与内网地址,不要留 0.0.0.0
bind 127.0.0.1 192.168.1.10
# 关闭保护模式下仍会放行的默认通路,显式收紧
protected-mode yes
# 仅监听本地 Unix socket 时可彻底禁用 TCP
port 6379
bind 必须写具体内网 IP,不要用注释绑定行的方式;若使用 Docker,务必用 -p 127.0.0.1:6379:6379 而不是裸 -p 6379:6379。
3. 开启强认证
# 生成高强度随机密码(32 位以上)
openssl rand -hex 32 # 例如输出 c9a7...(记录备用)
# 写入配置
requirepass "此处粘贴生成的密码"
# 重启后验证
redis-cli -a '你的密码' ping # 返回 PONG
redis-cli ping # 应返回 (error) NOAUTH
注意:requirepass 的密码会被 CONFIG GET 读取,务必同时禁用 CONFIG 命令(见步骤 4)。
4. 禁用危险命令
将高危命令 重命名或直接禁用(推荐禁用):
# 在 redis.conf 末尾追加
rename-command CONFIG ""
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command EVAL ""
rename-command EVALSHA ""
rename-command SLAVEOF ""
rename-command REPLICAOF ""
rename-command DEBUG ""
rename-command KEYS ""
若业务确实需要 EVAL(Lua 脚本)等命令,可改为重命名为随机串:
rename-command EVAL "ev4l_9f2k1q"
5. 持久化与主从安全
# 持久化文件权限收紧(默认 6379 端口 rdb 文件所在目录)
chmod 700 /var/lib/redis
chmod 600 /var/lib/redis/dump.rdb
# 主从复制启用认证,从库配置中指定
replicaof 192.168.1.10 6379
masterauth "你的密码"
# 关闭危险模块加载(若未使用)
# 注释掉 loadmodule 相关行
6. 防火墙与自动化检测
# iptables 仅允许内网访问 6379
iptables -A INPUT -p tcp --dport 6379 -s 192.168.1.0/24 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP
# 每日检测脚本(crontab 每 10 分钟检查未授权状态)
cat > /usr/local/bin/redis_check.sh <<'EOF'
#!/bin/bash
timeout 2 redis-cli -h 127.0.0.1 -p 6379 ping | grep -q PONG && echo "$(date) [WARN] Redis 未授权可访问!" >> /var/log/redis_check.log
EOF
chmod +x /usr/local/bin/redis_check.sh
echo "*/10 * * * * root /usr/local/bin/redis_check.sh" >> /etc/crontab
配置验证
# 1. 认证是否生效
redis-cli ping # NOAUTH
redis-cli -a 你的密码 ping # PONG
# 2. 危险命令是否被禁用
redis-cli -a 你的密码 CONFIG GET dir # (error) ERR unknown command
# 3. 端口暴露面
ss -tlnp | grep 6379 # 应只显示 127.0.0.1 / 内网 IP
# 4. 外部扫描(授权环境)
nmap -p 6379 --script redis-info <target-ip>
常见问题(FAQ)
Q1:禁用 CONFIG 后,应用无法设置过期策略怎么办?
业务运行期的 EXPIRE、TTL 等键级命令不受影响;只有服务端级的 CONFIG 被禁。运维需要改配置时,直接编辑配置文件并重启即可,不需要运行期 CONFIG SET。
Q2:为什么 6.0+ 的 ACL 也要配置?
6.0 引入 ACL 后,requirepass 只是「默认用户」口令。建议为每个应用创建独立账号并只授予最小命令集:
# 创建仅可操作指定库的应用账号
ACL SETUSER appuser on >app_pass ~app:* +get +set +del +expire +ttl +exists +ping
# 验证
redis-cli -u redis://appuser:app_pass@127.0.0.1:6379/0 ping
Q3:集群或哨兵模式下 rename-command 会破坏通信吗?
会。集群节点间使用 CLUSTER、哨兵使用 SLAVEOF/CONFIG 等内部命令,直接禁用会导致故障切换异常。集群/哨兵环境建议只做 bind + requirepass + ACL,危险命令改用网络层 ACL(云安全组仅放行内网)兜底。
总结
Redis 加固按「网络隔离 → 强认证 → 命令收敛 → 运行监控」四层落地:bind 绑定内网、32 位随机密码、禁用 CONFIG/EVAL/SLAVEOF 等危险命令,并配合检测脚本持续巡检。完成上述配置后,未授权访问与主从复制 RCE 两条主流攻击链均被切断。高版本建议同时启用 ACL 实现细粒度权限。