Redis 安全配置
Redis 默认配置并不安全,本章介绍如何配置 Redis 的安全性,包括认证、访问控制、网络安全等。
安全概述
Redis 的安全风险
┌─────────────────────────────────────────────────────────────┐
│ Redis 安全风险 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 无认证风险 │
│ ├── 默认无密码 │
│ └── 任何人可连接执行命令 │
│ │
│ 2. 网络暴露风险 │
│ ├── 绑定 0.0.0.0 暴露给所有网络 │
│ └── 互联网可访问危险 │
│ │
│ 3. 命令风险 │
│ ├── FLUSHALL 删除所有数据 │
│ ├── CONFIG 修改配置 │
│ └── DEBUG 调试命令 │
│ │
│ 4. 数据风险 │
│ ├── 敏感数据明文存储 │
│ └── 未加密传输 │
│ │
└─────────────────────────────────────────────────────────────┘
安全配置原则
- 最小权限原则:只授予必要的权限
- 默认拒绝原则:默认禁止所有访问,按需开放
- 纵深防御原则:多层安全措施
- 审计原则:记录所有操作
认证配置
设置密码
配置文件方式:
# redis.conf
# 设置密码(Redis 6.0 之前)
requirepass your_strong_password_here
# Redis 6.0+ 使用 ACL(推荐)
# 创建用户并设置密码
user default on >your_strong_password ~* &* +@all
命令行方式:
# Redis 6.0 之前
127.0.0.1:6379> CONFIG SET requirepass "your_strong_password"
OK
# 连接时需要认证
127.0.0.1:6379> AUTH your_strong_password
OK
密码策略
# 好的密码
requirepass "Xk9#mP2$vL5@nQ8!wR3&"
# 不好的密码
requirepass "123456" # 太简单
requirepass "password" # 常见密码
requirepass "redis123" # 包含服务名
连接认证
# 方式一:连接后认证
redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> AUTH password
# 方式二:连接时认证
redis-cli -h 127.0.0.1 -p 6379 -a your_password
# 方式三:使用环境变量(更安全)
export REDISCLI_AUTH=your_password
redis-cli -h 127.0.0.1 -p 6379
ACL 访问控制(Redis 6.0+)
ACL 概述
Redis 6.0 引入了 ACL(Access Control List),Redis 7.0 进一步升级为 ACL v2,支持了基于选择器(Selectors)的更复杂规则:
# 查看 ACL 列表
127.0.0.1:6379> ACL LIST
1) "user default on #hash... ~* &* +@all"
# 查看所有用户
127.0.0.1:6379> ACL WHOAMI
"default"
ACL v2 关键增强 (Redis 7.0+)
ACL v2 允许为一个用户定义多组相互独立的权限规则(Selectors):
# 创建具有多重选择器的用户
# 第一组权限:对 cache:* 拥有读写全权
# 第二组权限:对 meta:* 只能读取
ACL SETUSER app_multi on >pass123 ~cache:* +@all (~meta:* +@read)
优势:极大地增强了 Redis 在多租户、复杂微服务架构下的隔离能力和安全性。
用户管理
# 创建用户
127.0.0.1:6379> ACL SETUSER alice on >password123 ~* +@all
OK
# 查看用户
127.0.0.1:6379> ACL GETUSER alice
1) "flags"
2) 1) "on"
3) "passwords"
4) 1) "hash..."
5) "commands"
6) "+@all"
7) "keys"
8) "~*"
# 禁用用户
127.0.0.1:6379> ACL SETUSER alice off
OK
# 删除用户
127.0.0.1:6379> ACL DELUSER alice
(integer) 1
权限语法
用户配置格式:
ACL SETUSER username [options]
选项说明:
on/off - 启用/禁用用户
>password - 设置密码
#hash - 设置密码哈希
~pattern - 允许访问的键模式
resetkeys - 重置键模式
+command - 允许命令
-command - 禁止命令
+@category - 允许命令类别
-@category - 禁止命令类别
+@all - 允许所有命令
-@all - 禁止所有命令
nopass - 无需密码
命令类别
# 查看所有类别
127.0.0.1:6379> ACL CAT
1) "admin"
2) "bitmap"
3) "connection"
4) "dangerous"
5) "hash"
...
# 查看类别包含的命令
127.0.0.1:6379> ACL CAT dangerous
1) "flushall"
2) "flushdb"
3) "config"
4) "debug"
5) "shutdown"
...
ACL 配置示例
# 只读用户
127.0.0.1:6379> ACL SETUSER readonly on >password ~* +@read +@connection
OK
# 写入用户(不能执行危险命令)
127.0.0.1:6379> ACL SETUSER writer on >password ~* +@all -@dangerous
OK
# 只能访问特定键的用户
127.0.0.1:6379> ACL SETUSER cache_user on >password ~cache:* +@all
OK
# 管理员用户
127.0.0.1:6379> ACL SETUSER admin on >admin_password ~* +@all
OK
# 应用程序用户(只能访问特定前缀的键)
127.0.0.1:6379> ACL SETUSER app1 on >app1_pass ~app1:* +@all
OK
ACL 持久化
# 保存 ACL 配置到文件
127.0.0.1:6379> ACL SAVE
OK
# 从文件加载 ACL 配置
127.0.0.1:6379> ACL LOAD
OK
配置文件方式:
# redis.conf
# ACL 文件路径
aclfile /etc/redis/users.acl
users.acl 文件内容:
user admin on >admin_password ~* &* +@all
user readonly on >readonly_password ~* +@read +@connection
user app1 on >app1_password ~app1:* +@all -@dangerous
网络安全
绑定地址
# redis.conf
# 只绑定本地地址(推荐)
bind 127.0.0.1
# 绑定特定 IP
bind 192.168.1.100
# 绑定多个地址
bind 127.0.0.1 192.168.1.100
# 不要绑定所有地址(危险)
# bind 0.0.0.0
保护模式
# redis.conf
# 启用保护模式(默认)
# 保护模式开启时,如果未设置密码且绑定本地地址,只允许本地连接
protected-mode yes
端口配置
# 使用非默认端口
port 6380
# 隐藏 Redis 特征
# 修改端口可以避免自动扫描
防火墙配置
# Linux iptables
# 只允许特定 IP 访问
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 6379 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP
# Ubuntu ufw
sudo ufw allow from 192.168.1.0/24 to any port 6379
sudo ufw deny 6379
TLS/SSL 加密(Redis 6.0+)
# redis.conf
# 启用 TLS
tls-port 6380
tls-cert-file /path/to/redis.crt
tls-key-file /path/to/redis.key
tls-ca-cert-file /path/to/ca.crt
# 客户端证书验证
tls-auth-clients optional
tls-auth-clients no
# TLS 协议版本
tls-protocols "TLSv1.2 TLSv1.3"
连接 TLS 端口:
redis-cli --tls --cert /path/to/client.crt --key /path/to/client.key --cacert /path/to/ca.crt -p 6380
命令安全
禁用危险命令
# redis.conf
# 重命名或禁用命令
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command DEBUG ""
rename-command SHUTDOWN ""
rename-command KEYS ""
# 或者重命名为复杂名称
rename-command FLUSHDB "a1b2c3d4e5f6_FLUSHDB"
危险命令列表
| 命令 | 风险 | 说明 |
|---|---|---|
FLUSHALL | 极高 | 删除所有数据库的所有键 |
FLUSHDB | 极高 | 删除当前数据库的所有键 |
CONFIG | 高 | 查看/修改配置 |
DEBUG | 高 | 调试命令 |
SHUTDOWN | 高 | 关闭服务器 |
KEYS | 中 | 阻塞式列出所有键 |
MONITOR | 中 | 监控所有命令 |
使用 ACL 限制命令
# 禁止特定命令
127.0.0.1:6379> ACL SETUSER app_user on >password ~* +@all -FLUSHALL -FLUSHDB -CONFIG
OK
审计日志
慢查询日志
# redis.conf
# 慢查询阈值(微秒)
slowlog-log-slower-than 10000
# 慢查询日志最大长度
slowlog-max-len 128
查看慢查询:
127.0.0.1:6379> SLOWLOG GET 10
1) 1) (integer) 1
2) (integer) 1609459200
3) (integer) 15000
4) 1) "KEYS"
2) "*"
5) "127.0.0.1:54321"
6) "user1"
命令监控
# 监控所有命令(慎用,影响性能)
127.0.0.1:6379> MONITOR
OK
1609459200.123456 [0 127.0.0.1:54321] "SET" "key" "value"
1609459200.234567 [0 127.0.0.1:54321] "GET" "key"
安全最佳实践
1. 网络层面
# 部署架构建议
┌─────────────────────────────────────────────────────────────┐
│ 安全部署架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 互联网 │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 防火墙 │ 只开放必要端口 │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ 应用服务器 │ 内网通信 │
│ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Redis │ 绑定内网地址,设置密码 │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2. 配置检查清单
# 安全配置检查清单
□ 设置强密码
□ 绑定内网地址
□ 启用保护模式
□ 禁用或重命名危险命令
□ 配置 ACL(Redis 6.0+)
□ 配置防火墙规则
□ 启用 TLS(生产环境)
□ 定期审计访问日志
□ 定期更新 Redis 版本
3. 客户端安全
import redis
import os
# 不要硬编码密码
# 不好的做法
r = redis.Redis(password="hardcoded_password")
# 好的做法:使用环境变量
r = redis.Redis(
host=os.getenv('REDIS_HOST', 'localhost'),
port=int(os.getenv('REDIS_PORT', 6379)),
password=os.getenv('REDIS_PASSWORD'),
ssl=True, # 生产环境启用 SSL
ssl_cert_reqs='required'
)
4. 应用层安全
import redis
class SecureRedis:
def __init__(self, host, port, password, username=None):
self.r = redis.Redis(
host=host,
port=port,
password=password,
username=username,
decode_responses=True
)
def safe_get(self, key):
"""安全的获取值,避免敏感信息泄露"""
try:
return self.r.get(key)
except redis.AuthenticationError:
raise Exception("认证失败")
except redis.ConnectionError:
raise Exception("连接失败")
def safe_set(self, key, value, ttl=None):
"""安全的设置值"""
if ttl:
self.r.setex(key, ttl, value)
else:
self.r.set(key, value)
安全配置示例
完整配置文件
# redis.conf - 安全配置
# 网络配置
bind 127.0.0.1 192.168.1.100
port 6379
protected-mode yes
# 认证配置
requirepass Xk9#mP2$vL5@nQ8!wR3&
# ACL 配置(Redis 6.0+)
aclfile /etc/redis/users.acl
# 禁用危险命令
rename-command FLUSHDB ""
rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command DEBUG ""
rename-command KEYS ""
# 慢查询日志
slowlog-log-slower-than 10000
slowlog-max-len 128
# TLS 配置(生产环境)
# tls-port 6380
# tls-cert-file /etc/redis/redis.crt
# tls-key-file /etc/redis/redis.key
# tls-ca-cert-file /etc/redis/ca.crt
ACL 配置文件
# /etc/redis/users.acl
# 管理员用户
user admin on >admin_strong_password ~* &* +@all
# 只读用户
user readonly on >readonly_password ~* +@read +@connection
# 应用用户
user app1 on >app1_password ~app1:* +@all -@dangerous
user app2 on >app2_password ~app2:* +@all -@dangerous
# 监控用户
user monitor on >monitor_password ~* +@read +@connection +INFO +SLOWLOG
小结
本章我们学习了:
- 认证配置:密码设置和连接认证
- ACL 访问控制:用户管理和权限配置
- 网络安全:绑定地址、保护模式、TLS
- 命令安全:禁用危险命令
- 审计日志:慢查询和命令监控
- 最佳实践:安全检查清单和配置示例
练习
- 为 Redis 设置强密码
- 使用 ACL 创建只读用户
- 配置防火墙规则限制访问
- 禁用 FLUSHALL 和 CONFIG 命令