防止恶意脚本注入 Redis 消息队列,核心是从服务端禁用高危命令、强制认证绑定内网、消费者端校验消息内容,三者缺一不可。
先说结论:Redis 消息队列的注入风险主要来自未授权访问、PUBLISH 命令滥用和 Lua 脚本参数拼接,必须从网络层、认证层、应用层同时加固。
- 先判断:检查 Redis 是否开启密码认证、是否绑定公网地址、是否禁用高危命令
- 优先做:禁用或重命名 CONFIG/EVAL 等命令,设置强密码,限制访问 IP,Redis 6.0+ 建议使用 ACL
- 再验证:用 redis-cli 交互式测试未授权访问是否被阻止,检查消息消费端是否有长度和格式校验
服务端核心配置加固
以下是可直接用于加固 Redis 消息队列的关键配置和命令,注意避免破坏业务功能:
1. 禁用或重命名高危命令(redis.conf):
生产环境禁用 CONFIG、DEBUG、FLUSHALL 等高危命令。对于消息队列业务,不要直接禁用 PUBLISH,否则业务中断,建议重命名为复杂字符串或配合 ACL 使用。
rename-command CONFIG "" rename-command DEBUG "" rename-command FLUSHALL "" rename-command EVAL "" rename-command PUBLISH "pub_safe_2024_xyz"
2. 启用密码认证:
requirepass YourStrongPassword123!
3. 限制监听地址:
默认绑定本地,容器或内网多机部署需绑定具体内网 IP,严禁 bind 0.0.0.0。
bind 127.0.0.1 192.168.1.100
4. Redis 6.0+ ACL 权限最小化配置:
如果版本支持,建议创建专用账号,仅允许访问特定频道和命令。
ACL SETUSER mq_user on >StrongPassword123 ~* +@read +@write +publish -@dangerous
网络层与防火墙配置
1. 主机防火墙(iptables/ufw):
在 Redis 服务器所在的主机上配置防火墙规则,限制只有受信任的 IP 地址能够访问 Redis 端口。
UFW 示例:
sudo ufw deny 6379 sudo ufw allow from 192.168.1.0/24 to any port 6379
iptables 示例:
iptables -A INPUT -p tcp `--dport` 6379 -s 192.168.1.0/24 -j ACCEPT iptables -A INPUT -p tcp `--dport` 6379 -j DROP
2. Docker 环境网络隔离:
容器化部署时,不要使用 host 网络模式,创建专用网络。
docker network create redis-net docker run -d `--network` redis-net `--name` redis redis:latest
消费者端消息校验(Python 示例)
所有 SUBSCRIBE 客户端在接收消息后必须立即做校验,伪代码无法落地,以下是可运行的 Python 逻辑:
import redis
import json
ALLOWED_FIELDS = {'id', 'action', 'payload'}
MAX_MSG_LENGTH = 1024 * 1024 # 1MB
def process_message(msg):
# 1. 长度校验
if len(msg) > MAX_MSG_LENGTH:
print("Drop: Message too long")
return
# 2. 格式校验
try:
data = json.loads(msg)
except json.JSONDecodeError:
print("Drop: Invalid JSON")
return
# 3. 字段白名单过滤
filtered = {k: v for k, v in data.items() if k in ALLOWED_FIELDS}
# 4. 业务逻辑处理
handle_business_logic(filtered)
r = redis.Redis(host='localhost', port=6379, password='YourStrongPassword123!')
pubsub = r.pubsub()
pubsub.subscribe('my_channel')
for message in pubsub.listen():
if message['type'] == 'message':
process_message(message['data'])怎么验证是否生效
1. 验证未授权访问被阻止:
注意:不要使用 -a 参数传递密码,避免在进程列表暴露。
redis-cli ping # 应返回:(error) NOAUTH Authentication required. redis-cli 127.0.0.1:6379> AUTH YourStrongPassword123! # 应返回:OK
2. 验证高危命令被禁用:
redis-cli 127.0.0.1:6379> AUTH YourStrongPassword123! 127.0.0.1:6379> CONFIG GET maxmemory # 应返回:(error) ERR unknown command 'CONFIG'
3. 验证监听地址:
netstat -tlnp | grep redis # 应只显示 127.0.0.1:端口 或内网 IP,不应显示 0.0.0.0
4. 验证消息消费端校验:
发送超长消息或畸形 JSON 到队列,观察消费者是否正确丢弃并记录日志。检查应用日志中是否有消息长度超限或解析失败的记录。
常见坑
1. 只靠应用层过滤不够
攻击者绕过业务代码直连 Redis 执行 PUBLISH 后,恶意消息会直接抵达消费者。此时再做校验已晚,必须从服务端掐断入口。
2. Lua 脚本中信任 ARGV
很多人误以为只传给 eval 的 ARGV 是安全的,其实不然。如果脚本里写了 loadstring("return "..ARGV[1]),攻击者可以传入恶意代码。所有用户输入必须严格作为 ARGV 或 KEYS 传入,且在 Lua 脚本里只作值比较,绝不参与代码生成。
3. 错误响应泄露信息
避免在脚本里做尝试性调用,比如用 pcall 包一层然后根据成功与否分支逻辑,这容易被时序攻击利用。错误本身可能泄露信息,比如通过响应时间或错误码判断 key 是否存在。
4. 频道名也是攻击面
Redis 不校验频道名合法性,攻击者可批量创建规律性频道刷屏。需定期扫描异常频道名并清理。
5. 密码硬编码
密码绝不可硬编码在前端或公开配置中,应使用环境变量或密钥管理服务。
6. 以 root 身份运行 Redis
请以较低权限账号运行 Redis 服务,并禁用该账号的登录权限。如果 Redis 以 root 身份运行,黑客可以给 root 账户写入 SSH 公钥文件,直接通过 SSH 登录控制服务器。
参考来源
- Redis Official Documentation - Security
- Redis Official Documentation - ACL
- CVE Details - Redis Vulnerabilities
- OWASP Top 10 - Injection