如何防止恶意脚本注入 Redis 消息队列进行安全加固?

文章导读
防止恶意脚本注入 Redis 消息队列,核心是从服务端禁用高危命令、强制认证绑定内网、消费者端校验消息内容,三者缺一不可。
📋 目录
  1. A 服务端核心配置加固
  2. B 网络层与防火墙配置
  3. C 消费者端消息校验(Python 示例)
  4. D 怎么验证是否生效
  5. E 常见坑
  6. F 参考来源
A A

防止恶意脚本注入 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 权限最小化配置:

如果版本支持,建议创建专用账号,仅允许访问特定频道和命令。

如何防止恶意脚本注入 Redis 消息队列进行安全加固?
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. 验证未授权访问被阻止:

如何防止恶意脚本注入 Redis 消息队列进行安全加固?

注意:不要使用 -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 脚本里只作值比较,绝不参与代码生成。

如何防止恶意脚本注入 Redis 消息队列进行安全加固?

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