redis防御加固与安全基线

攻击 = 允许被网络访问 + 允许执行危险操作 + 操作落在危险位置。那防御就是三件事:

  1. 网络层:不让他连得上(bind、防火墙、不要裸奔公网)。

  2. 认证与授权层:就算连上,也要密码 / ACL 挡住危险命令。

  3. 系统层:就算命令执行了,低权限用户 + 最小目录写权限,让他写不了能被执行的文件。


1. 先看现状:现在的 Redis 有多裸?

任何加固的第一步是盘点现状。管理员先自查:

复制代码
# 1) 谁在监听、监听在哪张网卡
ss -tlnp | grep 6379        # 看是否 0.0.0.0 / *(公网)在听
# 或
netstat -an | grep 6379
​
# 2) 关键配置现状
redis-cli CONFIG GET bind
redis-cli CONFIG GET protected-mode
redis-cli CONFIG GET requirepass
redis-cli CONFIG GET dir
redis-cli INFO server | grep redis_version
​
# 3) 当前用户/权限
ps -ef | grep redis-server | grep -v grep   # redis 以什么用户跑?

我怎么知道 Redis 是否暴露在公网?

上面 ss 看监听地址:0.0.0.0:6379*:6379 = 所有网卡都在听(含公网)。也可以从另一台机器 telnet 公网IP 6379 试连通性。安全工具如 shodan/fofa 能直接搜到全网暴露的 6379------那些基本都是被攻击重灾区。


2. 网络层加固:让攻击者"连不上"

2.1 bind:只监听需要的网卡

复制代码
# redis.conf 里
# 只允许本机访问(最安全,开发/单机推荐)
bind 127.0.0.1
​
# 只允许内网特定 IP 访问(生产常用,按需改)
bind 127.0.0.1 10.10.10.5
​
# 千万别这样(监听所有网卡,等于暴露公网)
# bind 0.0.0.0
# 或注释掉 bind

不写 bind 0.0.0.0 时,老版本默认可能监听所有网卡------所以显式写明 bind 是好习惯。

2.2 protected-mode:兜底开关,务必保持 yes

复制代码
protected-mode yes

protected-mode 只在"没设密码 + 非本机连接"时才拦。它是兜底 不是万能。正确姿势:bind 收紧 + 设密码 + protected-mode yes 三者一起上,别只靠一个。

2.3 防火墙 / 安全组

即使 bind 失误,网络层还有最后一道闸:

复制代码
# 只允许信任网段访问 6379
iptables -A INPUT -p tcp --dport 6379 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP
# 云上:安全组入方向不向 0.0.0.0/0 放行 6379

3. 认证与授权:连上了也要拦

3.1 requirepass:设置访问密码(最基础)

Redis 6 之前只有这一种认证方式,所有客户端共用一个密码。

复制代码
# redis.conf
requirepass 一个足够强、且不重复使用的密码

验证:

复制代码
redis-cli -p 6379 ping
# (error) NOAUTH Authentication required.   ← 没密码进不去,攻击断一条腿
redis-cli -p 6379 -a 密码 ping
# PONG

设了 requirepass 之后,主从/哨兵之间也要配密码(masterauth),否则从库连不上主库------这属于运维细节,但漏配会导致复制失败告警。

3.2 ACL:细粒度控制"谁能执行哪些命令"(Redis 6+,强烈推荐)

requirepass 是"一刀切",ACL 才是现代 Redis 的正解:可以建多个用户,每个用户指定能访问哪些 key、执行哪些命令

ACL 基本模型:

复制代码
ACL SETUSER 用户名 规则...

常用规则:

规则 含义
on / off 启用 / 停用该用户
>密码 设置密码
~pattern 允许访问匹配的 key(~* 所有;~cache:* 只 cache 前缀)
+命令 / -命令 允许 / 禁止某命令
+@类别 / -@类别 按类别批量放行/禁止(如 +@read -@admin
allkeys / allcommands 等价 ~* / +@all
nopass 免密(default 用户默认 nopass,危险)

创建一个只能读 cached:*、只能执行少量命令的只读用户(演示,真实按业务改):

复制代码
# 建用户:demo,密码 s3cretPwd,只能访问 cached:*,只允许 ping/get/set
redis-cli -p 6379 ACL SETUSER demo on '>s3cretPwd' '~cached:*' '+ping' '+get' '+set'
# 查看所有用户
redis-cli -p 6379 ACL LIST
# 输出示例:
# user default on nopass sanitize-payload ~* &* +@all          ← 默认超级用户
# user demo on sanitize-payload #hash... ~cached:* resetchannels -@all +get +set +ping

用 demo 用户连:

复制代码
redis-cli -p 6379 --user demo -a s3cretPwd
# 能 get cached:xxx、set cached:yyy、ping
# 但不能 KEYS、不能 FLUSHALL、不能 CONFIG → 会被 (error) NOPERM 拒绝

ACL 和 requirepass 能同时用吗?

能。requirepass 本质是给 default 用户设密码。Redis 6+ 更推荐直接用 ACL 管理用户,可以保留 default 强密码,另建只读/最小权限用户给不同业务方。

为什么 ACL 能防住攻击?

前面 所有 getshell,最后都依赖 CONFIG / BGSAVE / REPLICAOF / MODULE / EVAL 这类高危命令 。用 ACL 把业务账号限制成只读 + 只碰业务 key,攻击者拿到这个账号也调不动任何危险命令

3.3 禁用/改名高危命令(无 ACL 的版本也能用)

老版本没有 ACL,用 rename-command 把危险命令改名或直接禁用(只能写在 redis.conf 里,重启生效,CONFIG SET 改不了):

复制代码
# redis.conf
# 把危险命令禁掉(改名成空字符串 = 禁用)
rename-command CONFIG ""
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command EVAL ""
rename-command SCRIPT ""
rename-command SHUTDOWN ""
​
# 或改成只有你知道的暗名(如果业务确实要用)
rename-command CONFIG "r3dis_c0nfig_9527"

改名命令的坑

  1. 主从、哨兵、客户端里如果写了 CONFIG,改名后全都要跟着改,否则复制/运维脚本会挂;

  2. rename-command 只在配置里生效,无法用 CONFIG SET 在线改;

  3. 改名前先在测试环境验证业务兼容性。


4. 系统层:就算命令执行了,也"写不了 / 干不了活"

4.1 用低权限用户跑 Redis

这是最容易被忽略、也最有效的一条。 Redis 若以 root 跑,写 crontab / SSH 公钥 / WebShell 全都有权限;用普通用户跑,那些系统目录根本写不进去。

复制代码
# 建一个无登录、最小权限的 redis 用户
useradd -r -s /sbin/nologin redis
mkdir -p /var/lib/redis /var/log/redis /etc/redis
chown redis:redis /var/lib/redis /var/log/redis /etc/redis
​
# redis.conf 里指定
user redis
​
# 或 systemd 单元里 User=redis

为什么有些未授权 Redis 打不出 getshell?

很多时候不是命令被禁,而是 Redis 跑在 redis 用户下,/root/.ssh/var/spool/cron、web 目录它都没权限写------这正是低权限运行的防御价值。

4.2 数据目录与落盘位置最小化

  • 给 Redis 一个独立且无执行权限 的数据目录(如 /var/lib/redis),不要把 dir 指到 web 根目录。

  • 即使攻击者改了 dir,目录权限 + SELinux/AppArmor 也能二次拦截。

  • 定期检查 dir 里有没有异常文件(攻击者落盘的 shell.php 之类)。

4.3 日志与监控

  • 开 Redis 日志(logfile),记录连接和命令。

  • 监控 6379 的连接来源、异常 KEYS * / CONFIG SET / FLUSHALL / REPLICAOF 命令。

  • 对外部发起的长时间连接、异常大流量保持警惕。


5. 云上/容器部署的额外注意

复制代码
□ Docker:端口映射别裸开 6379(-p 6379:6379 且无密码 = 灾难);用 --network 内网或仅本机
□ k8s:Redis 服务不要暴露成 NodePort/LoadBalancer 到公网
□ 云托管 Redis(如云厂商):用安全组/VPC 隔离 + 开密码 + 开审计
□ 公网示例默认账号/端口:第一时间改端口或至少加密码,别用默认 6379 裸奔

6. 最小加固清单

按顺序做,前三条性价比最高:

复制代码
# ===== redis.conf 最小安全配置 =====
bind 127.0.0.1                        # 1. 不对外监听(或用内网IP)
protected-mode yes                    # 2. 保护模式兜底
requirepass 换成超强随机密码          # 3. 无密码 = 未授权访问(高危)
​
# 4. 若有 ACL,给业务用最小权限用户(可选但推荐)
# 5. 禁用/改名危险命令(老版本)
rename-command CONFIG ""
rename-command FLUSHALL ""
​
# 6. 系统层
#    用非 root 用户跑 redis
#    数据目录独立且不可写危险位置
# 7. 网络层
#    防火墙/安全组只放行信任来源

即使只做 1+2+3,之前的四条 getshell 全都会断在第 1 步(连不上/要密码)。再做 5,连"拿到密码但想用危险命令"也被断。这就是分层防御:每一层都独立地挡住一种攻击路径。


7. 攻防对照表

攻击手法(前面的篇目) 核心依赖 对应防御
未授权访问(03) bind 0.0.0.0 + 无密码 bind 收紧 + protected-mode + requirepass/ACL
爆破弱口令 弱密码 强密码 + 限制失败次数/来源 IP + 日志监控
写 crontab/公钥/WebShell(03) CONFIG SET dir + 高权限 + 落盘 禁用 CONFIG + 非 root 跑 + 目录权限/SELinux
主从复刻 RCE(03) REPLICAOF + 模块加载 + 可反连 禁用/改名 REPLICAOF + 版本升级 + ACL + 出网限制
SSRF 打 Redis(04) 内网可达 + 无密码 网络隔离 + 密码 + SSRF 点本身修复(你 SSRF 篇已讲)
信息泄露(读业务数据) 可连接可读 ACL 最小权限 + 敏感数据加密存储/不要明文进 Redis
DoS(KEYS */灌数据) 单线程 + 可执行 禁 KEYS/FLUSHALL + 限内存 maxmemory + 连接数限制

8. 失陷后的排查要点

如果怀疑 Redis 失陷,冷静按下面查(配合应急响应流程):

  1. 看有没有被写文件 :检查 CONFIG GET dir 当前值、/var/spool/cron*/root/.ssh/authorized_keys、web 根目录的陌生 .php/.so

  2. 看有没有被改配置CONFIG GET requirepass、ACL LIST(是否多了陌生用户)。

  3. 看有没有被加载模块MODULE LIST(Redis 4+)。

  4. 看主从关系INFO replication 是否被改成了某陌生主的从库。

  5. 看日志:redis.log、系统登录日志、反弹连接的连接记录。

  6. 紧急处置:断网隔离 → 改密码/重建实例 → 取证 → 复盘加固。

处置时优先"保留现场取证",别急着 flushall(会把攻击痕迹也清了)。


9. 小结

防御的本质不是背命令,而是分层

复制代码
网络层(连不上) → 认证层(连上也要密码) → 授权层(危险命令被禁)
→ 系统层(命令执行了也写不了危险位置) → 监控审计(打进来能发现)

攻防其实是同一张地图,攻方从外往内一层层找"允许",守方从内往外一层层设"不允许"。


全系列自测

  1. 用自己的话,把"未授权 Redis 为什么危险"从网络→认证→写文件→执行,完整讲一遍因果链。

  2. 给一个"只能跑缓存、永远不该被当数据库写"的 Redis 写一份最小安全配置。

  3. 假设你是蓝队,收到"内网 6379 裸奔"告警,写出你从确认到处置的完整动作清单。

  4. 说出 ACL 里限制一个业务账号"只能读某前缀 key、不能用 CONFIG/FLUSHALL/EVAL"的完整命令。

  5. 解释为什么"Redis 用 root 跑"比"没设密码"在某些场景更致命。

相关推荐
lhldsg1 小时前
全民健身解决方案小程序开发:从0到1的技术实战
java·数据库·需求分析
SendTomo1 小时前
【技术交流】从0到1构建一个汉字学习平台:汉字吧(hanzi8.com)的技术架构猜想
redis·mysql·nginx·php·个人开发
IT大白鼠1 小时前
MySQL 分布式集群系列 · 第四篇——实操部署指南:从零搭建生产级 MySQL NDB 集群
数据库·分布式·mysql
IT大白鼠2 小时前
MySQL 分布式集群系列 · 第三篇——核心原理精讲:NDB 自动分片、多主写入与数据同步
数据库·分布式·mysql
Elastic 中国社区官方博客2 小时前
教程:使用 ES|QL 进行威胁狩猎
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索·安全威胁分析
乐迪信息2 小时前
如何通过AI防爆摄像机精准判断船舶超速?
大数据·人工智能·算法·安全·目标跟踪
luiyarch3 小时前
汽车电子ISO 26262功能安全系列(第35期):配置管理与变更管理——给安全系统装上“时空穿梭机”
安全·汽车
斑马1394 小时前
Linux软件编程学习笔记(十三)——数据库
数据库·oracle
初願致夕霞4 小时前
MySQL_索引
数据库·mysql