【Redis从入门到精通】第08篇:Redis安全最佳实践——别让你的Redis裸奔在公网上
上一篇【第07篇】Redis命令速查手册——工作中最常用的80条命令下一篇【第09篇】深入Redis的灵魂——redisObject对象系统全解析摘要Redis默认安装是不设防的——不需要密码监听所有网络接口root权限运行。这导致全球数以万计的Redis实例暴露在公网上成为挖矿病毒、勒索软件、僵尸网络的温床。本文从一个真实案例开始系统梳理Redis安全配置的完整防线帮你设置强密码认证、正确绑定IP、重命名危险命令、配置ACL细粒度权限控制和TLS加密传输。最后给出一份可直接落地的安全配置Checklist和防火墙规则帮你在10分钟内把Redis武装到牙齿。一、血的教训2019年Redis挖矿病毒事件1.1 事件回顾2019年安全研究人员在全球范围内检测到大规模Redis未授权访问攻击。攻击者通过扫描IP段找到暴露在公网且无密码的Redis实例默认端口6379然后干了两件事写入SSH公钥用CONFIG SET修改Redis的数据目录到/root/.ssh/再用SET命令写入攻击者的公钥获取服务器root权限植入挖矿程序使用CONFIG SET修改crontab文件定时下载执行挖矿脚本攻击流程简图公网扫描 授权实现 ┌─────────┐ 扫描6379端口 ┌──────────┐ 无密码访问 ┌──────────┐ │ 攻击者 │ ───────────── │ Redis实例 │ ────────── │ 攻击者 │ └─────────┘ └──────────┘ └─────┬────┘ │ │ CONFIG SET dir /root/.ssh/ │ SET d2r3 \n\nssh-rsa AAAA... │ CONFIG SET dbfilename auth_keys │ │ │ SSH免密登录获取root权限 ◄─────────┘ │ 植入挖矿程序、勒索病毒这个漏洞本质上不是Redis的bug而是用户配置不当。Redis官方早就提供了密码认证功能requirepass但很多人图省事没配置或者把Redis暴露在公网上。⚠️ 注意即使现在Shodan搜索引擎上仍能搜到数万个无密码保护的Redis实例。如果你的Redis服务器被入侵攻击者能做的事情远不止挖矿——读你的业务数据、删库、篡改数据、植入后门后果不堪设想。1.2 风险评估风险等级场景可能后果高危Redis无密码 监听0.0.0.0 公网可达随时被入侵数据泄露服务器被控制中危Redis无密码 监听0.0.0.0 内网 防火墙未配置内网横向移动攻击低危Redis有密码 监听0.0.0.0 公网密码可能被暴力破解安全Redis有强密码 bind 127.0.0.1 ACL TLS攻击面最小化二、第一道防线网络隔离与绑定IP2.1 bind参数配置Redis的bind参数决定监听哪些网络接口。默认配置通常是# 危险配置 bind 0.0.0.00.0.0.0意味着监听所有网络接口包括公网IP。任何能ping通你服务器的人都能尝试连接Redis。正确的配置# 只监听本机回环地址 bind 127.0.0.1 # 如果需要内网访问指定内网IP bind 127.0.0.1 192.168.1.100 # 也可以绑定多个内网IP bind 127.0.0.1 10.0.1.5 10.0.2.5安全网络拓扑 ┌─────────────────────────────┐ │ 服务器 │ │ │ 互联网 ─── 防火墙 ─── 8080端口 ── Nginx (对外) │ │ 6379端口被防火墙拦截 │ │ │ │ ┌──────────────┐ │ │ │ App Server │── TCP 6379 ── │ │ └──────────────┘ 内网访问 │ │ bind: 127.0.0.1, 10.0.1.x │ │ Redis 只对内网开放 │ └─────────────────────────────────────┘2.2 protected-mode保护模式Redis 3.2之后默认启用了protected-mode当以下条件都满足时会拒绝外部连接bind没有被显式设置requirepass没有设置密码连接来自非回环地址# 保护模式Redis 3.2 默认开启 protected-mode yes# 如果你远程连接无密码的Redis会收到错误redis-cli-h10.0.1.5-p6379# DENIED Redis is running in protected mode because...⚠️ 注意protected-mode是一种兜底保护但不是万能药。如果你显式设置了bind 0.0.0.0protected-mode就失效了。正确做法永远是明确配置bind requirepass。三、第二道防线密码认证3.1 requirepass配置# 设置密码redis.conf requirepass YourStr0ng!Passw0rd#2024 # 或者运行时设置 redis-cli CONFIG SET requirepass YourStr0ng!Passw0rd#2024 redis-cli CONFIG REWRITE # 持久化到配置文件连接时提供密码# 方式1-a 参数不推荐密码会出现在进程列表中redis-cli-aYourStr0ng!Passw0rd#2024# 方式2交互式认证推荐redis-cliAUTH YourStr0ng!Passw0rd#2024OK# 方式3环境变量 redis-cliREDISCLI_AUTHYourStr0ng!Passw0rd#2024redis-cli# 方式4URI方式连接redis-cli-uredis://:YourStr0ng!Passw0rd#2024127.0.0.1:63793.2 强密码建议# 错误示范 requirepass 123456 # 太简单 requirepass redis # 太明显 requirepass admin123 # 常见组合 # 正确示范 requirepass R3d!s_S3cur3_Pss_2024_XyZ # 特征16位以上、大小写字母、数字、特殊符号混合生成强密码的一个方法# Linux下生成32位随机密码openssl rand-base6432# 输出: K7mFpQ2xR9vL4nB8wT3jH5cA1dG6sY0UE...# 或者用Redis自带的echo$(head-c32/dev/urandom|base64)四、第三道防线重命名与禁用危险命令4.1 哪些命令是危险的命令危险等级原因FLUSHDB / FLUSHALL致命清空所有数据不可恢复CONFIG致命可以修改dir、dbfilename等配置写入任意文件DEBUG高危DEBUG SLEEP可堵塞服务DEBUG RELOAD重载RDBEVAL / EVALSHO高危可执行任意Lua脚本SHUTDOWN高危停止Redis服务BGSAVE / BGREWRITEAOF中等触发大量IO影响性能KEYS中等遍历所有key导致阻塞SLAVEOF中等变更主从关系4.2 rename-command配置# 重命名危险命令redis.conf rename-command CONFIG XyZ_Config_9a2b rename-command FLUSHDB XyZ_FlushDB_7c3d rename-command FLUSHALL XyZ_FlushAll_1e5f rename-command SHUTDOWN XyZ_Shutdown_4g8h rename-command DEBUG XyZ_Debug_6i9j rename-command EVAL XyZ_Eval_2k5l rename-command EVALSHA XyZ_EvalSha_3m1n # 彻底禁用重命名为空字符串 rename-command FLUSHALL rename-command FLUSHDB rename-command CONFIG rename-command SHUTDOWN 重命名后原来的命令名就失效了redis-cli FLUSHALL# (error) ERR unknown command FLUSHALLredis-cli XyZ_FlushAll_1e5f# OK如果知道新名字才能执行4.3 重命名的注意事项⚠️ 注意重命名可能会导致一些监控工具和运维脚本无法正常工作因为它们在内部调用了这些命令。比如Redis Sentinel内部会使用CONFIG命令如果你把CONFIG禁用Sentinel就没法用了。建议的做法是只对外部客户端禁用的命令进行重命名Sentinel / Cluster 场景下不要禁用CONFIG升级到Redis 6.0使用ACL替代rename-command五、第四道防线ACL细粒度权限控制Redis 6.0Redis 6.0引入的ACLAccess Control List彻底改变了Redis的单密码认证模式让你可以为不同用户设置不同的命令和key访问权限。5.1 ACL核心概念传统模式Redis 6.0之前 所有客户端 ── AUTH password ── Redis全权限 ACL模式Redis 6.0 应用A ── AUTH user_app password ── 只能读写 app:* 开头的key 管理D ── AUTH user_admin password ── 只能读不能写 运维O ── AUTH user_ops password ── 只有读写权限无CONFIG等管理权限 default用户 ── 无权限或最低权限5.2 ACL命令详解# 1. 查看ACL列表redis-cli ACL LIST# 返回: 当前所有用户及其权限规则# 2. 查看ACL分类命令redis-cli ACL CAT# 列出所有命令分类redis-cli ACL CAT dangerous# 列出dangerous分类中的命令redis-cli ACL CAT admin# 列出admin分类中的命令# 3. 创建只读用户redis-cli ACL SETUSER reader ONreadpass ~* read -write -dangerous# 解释# ON → 激活用户# readpass → 设置密码为 readpass# ~* → 允许访问所有key# read → 允许read分类中的所有命令# -write → 禁止write分类中的所有命令# -dangerous → 禁止危险命令# 4. 创建仅能操作特定前缀key的用户redis-cli ACL SETUSER app_user ONapppass ~app:* all -admin -dangerous# 解释# ~app:* → 只能访问 app:* 开头的key# all → 允许所有非管理命令# -admin → 禁止管理命令# -dangerous → 禁止危险命令# 5. 创建管理员用户redis-cli ACL SETUSER admin ONadminpass ~* all# 6. 为default用户设置密码限制默认用户权限redis-cli ACL SETUSER default ONdefaultpass ~* all -dangerous# 7. 查看某个用户的权限redis-cli ACL GETUSER app_user# 8. 删除用户redis-cli ACL DELUSER reader# 9. 保存ACL到文件redis-cli ACL SAVE# 10. 从文件加载ACLredis-cli ACL LOAD5.3 ACL权限模型图┌────────────────────────────────┐ │ ACL 权限模型 │ ├──────────┬─────────────────────┤ │ ON/OFF │ 用户激活/禁用 │ │ pass │ 密码设置 │ │ ~pattern│ Key访问模式 │ │ cmd │ 允许的命令 │ │ -cmd │ 禁用的命令 │ │ cat │ 允许的命令分类 │ │ -cat │ 禁用的命令分类 │ │ pattern│ Pub/Sub频道模式 │ │ nopass │ 无密码不推荐 │ │ reset │ 重置用户权限 │ └──────────┴─────────────────────┘5.4 ACL命名方式最佳实践# 生产环境推荐的ACL配置示例# 1. 默认用户只给最低权限ACL SETUSER default OFF# 2. 应用用户按业务模块隔离ACL SETUSER svc_payment ONpyment_S3cur3!~payment:* all -admin -dangerous ACL SETUSER svc_order ON0rder_S3cur3!~order:* all -admin -dangerous ACL SETUSER svc_cache ONCche_S3cur3!~cache:* all -admin -dangerous# 3. 只读分析用户ACL SETUSER analyst ONAnlyst_R3ad!~* read -write -dangerous# 4. DBA运维用户不限制key但不能执行危险命令ACL SETUSER dba ONDB_Adm1n!~* all -dangerous-FLUSHDB-FLUSHALL# 5. 备份用户只能执行备份相关命令ACL SETUSER backup ONBckup_Dily!~* bgsave save lastsave info -all六、第五道防线TLS/SSL加密传输Redis 6.0支持原生TLS加密保护数据在传输过程中不被窃听或篡改。6.1 生成TLS证书# 1. 生成CA私钥和证书openssl genrsa-outca.key4096openssl req-x509-new-nodes-keyca.key-sha256-days3650\-outca.crt-subj/CNRedis CA# 2. 生成Redis服务器私钥和证书请求openssl genrsa-outredis.key2048openssl req-new-keyredis.key-outredis.csr\-subj/CNredis-server# 3. 用CA签发Redis服务器证书openssl x509-req-inredis.csr-CAca.crt-CAkeyca.key\-CAcreateserial-outredis.crt-days365-sha256# 4. 生成客户端证书可选双向TLS认证openssl genrsa-outclient.key2048openssl req-new-keyclient.key-outclient.csr\-subj/CNredis-clientopenssl x509-req-inclient.csr-CAca.crt-CAkeyca.key\-CAcreateserial-outclient.crt-days365-sha2566.2 Redis TLS配置# redis.conf port 0 # 关闭非TLS端口 tls-port 6380 # 启用TLS端口 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认证可选 tls-auth-clients yes # 要求客户端提供证书 # 性能优化 tls-protocols TLSv1.2 TLSv1.3 tls-ciphers DEFAULT tls-prefer-server-ciphers yes # 同时支持TLS和非TLS连接都开 # port 6379 # 普通端口 # tls-port 6380 # TLS端口6.3 客户端TLS连接# redis-cli TLS连接redis-cli--tls\--cert/etc/redis/tls/client.crt\--key/etc/redis/tls/client.key\--cacert/etc/redis/tls/ca.crt\-p6380# 使用URI方式redis-cli--tls-urediss://user:password127.0.0.1:6380Java客户端TLS配置// Lettuce TLS配置RedisURIuriRedisURI.Builder.redis(127.0.0.1,6380).withSsl(true).withPassword(your_password.toCharArray()).withVerifyPeer(false).build();RedisClientclientRedisClient.create(uri);// Jedis TLS配置JedisjedisnewJedis(127.0.0.1,6380,true);// true 启用SSL// 注意Jedis对TLS的支持有限建议用Lettuce七、Redis安全配置Checklist┌─────────────────────────────────────────────────────────────────────┐ │ Redis 安全配置检查清单 │ ├───┬──────────────────────────────────┬──────┬───────────────────────┤ │# │ 检查项 │ 状态 │ 说明 │ ├───┼──────────────────────────────────┼──────┼───────────────────────┤ │1 │ bind 是否只绑定了内网IP │ □ │ 至少包含 127.0.0.1 │ │2 │ requirepass 是否设置了强密码 │ □ │ 16位以上混合密码 │ │3 │ protected-mode 是否开启 │ □ │ Redis 3.2 默认开启 │ │4 │ 危险命令是否重命名或禁用 │ □ │ FLUSHALL/CONFIG等 │ │5 │ 是否配置了ACL访问控制 │ □ │ Redis 6.0推荐 │ │6 │ TLS是否启用 │ □ │ 生产环境跨网络时必选 │ │7 │ 防火墙规则是否到位 │ □ │ 6379端口不对公网开放 │ │8 │ 是否以非root用户运行Redis │ □ │ 创建专用redis用户 │ │9 │ 日志是否开启了 │ □ │ logfile /var/log/... │ │10 │ 是否禁用了CONFIG SET │ □ │ 或通过ACL限制 │ │11 │ 是否定期更新Redis版本 │ □ │ 关注CVE安全公告 │ │12 │ 是否设置了maxmemory限制 │ □ │ 防止内存耗尽 │ ├───┼──────────────────────────────────┼──────┼───────────────────────┤ │ │ 综合安全评分 │ /12 │ 每个□1分满分12分 │ └───┴──────────────────────────────────┴──────┴───────────────────────┘推荐的生产环境完整配置# 网络安全 bind 127.0.0.1 10.0.1.100 protected-mode yes port 6379 # 密码认证 requirepass R3d!s_Pr0d_Pss_2024_S3cur3! # 命令安全 rename-command FLUSHALL rename-command FLUSHDB rename-command CONFIG 00df2a_config_9b7c rename-command SHUTDOWN rename-command DEBUG rename-command EVAL 00df2a_eval_3e1a rename-command EVALSHA 00df2a_evalsha_5f6d # ACLRedis 6.0 aclfile /etc/redis/users.acl # TLS/SSL # tls-port 6380 # 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 # 运行安全 daemonize yes pidfile /var/run/redis/redis.pid logfile /var/log/redis/redis.log logLevel notice maxmemory 2gb maxmemory-policy allkeys-lru八、防火墙规则# iptables 规则 # 1. 禁止公网访问Redis端口最核心规则iptables-AINPUT-ptcp--dport6379-jDROP# 2. 只允许内网特定IP段访问iptables-AINPUT-ptcp-s10.0.0.0/8--dport6379-jACCEPT iptables-AINPUT-ptcp-s192.168.0.0/16--dport6379-jACCEPT iptables-AINPUT-ptcp-s127.0.0.1--dport6379-jACCEPT iptables-AINPUT-ptcp--dport6379-jDROP# 其他全部拒绝# 3. 保存规则iptables-save/etc/iptables/rules.v4# UFWUbuntu/Debian# 1. 默认拒绝Redis端口ufw deny6379# 2. 只开放给内网ufw allow from10.0.0.0/8 to any port6379ufw allow from192.168.0.0/16 to any port6379ufw allow from127.0.0.1 to any port6379# 3. 启用防火墙ufwenableufw status verbose云环境安全组配置规则方向协议端口来源动作入站TCP637910.0.0.0/8允许入站TCP6379127.0.0.1/32允许入站TCP63790.0.0.0/0拒绝出站TCP全部0.0.0.0/0允许总结Redis的安全配置没有技术门槛全是意识问题。十条核心原则记牢bind 只绑内网IP永远不要绑0.0.0.0设强密码16位以上混合字符开protected-mode多一层兜底保护禁危险命令FLUSHALL/CONFIG/DEBUG全关掉上ACL6.0给不同应用不同权限配防火墙6379不对公网开放非root运行创建独立的redis用户上TLS6.0跨网络传输加密加监控异常访问告警勤升级跟进安全补丁花10分钟把这10条配置到位你的Redis就能从裸奔变成武装到牙齿。上一篇【第07篇】Redis命令速查手册——工作中最常用的80条命令下一篇【第09篇】深入Redis的灵魂——redisObject对象系统全解析