不安全的 Redis 的特点
- Redis 所在机器有外网 IP
- Redis 使用默认端口 6379 启动,并且对外网开放
- Redis 以 root 身份启动
- Redis 没有设置密码
- Redis 的 bind 为
0.0.0.0
或""
案例:
2015年11月,全球数万个 Redis 遭受攻击,数据被清空,只有一个叫 crackit 键存在,其数据类似一个公钥,内容如下:
127.0.0.1:6379> get crackit
"\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsGWAoHYwBcnAkPaGZ565wPQ0Ap3K7zrf2v9p HPSqW+n8WqsbS+xNpvvcgeNT/fYYbnkUit11RUiMCzs5FUSI1LRthwt4yvpMMbNnEX6J/0W/0nlq PgzrzYflP/cnYzEegKlcXHJ2AlRkukNPhMr+EkZVyxoJNLY+MB2kxVZ838z4U0ZamlPEgzy+zA+oF 0JLTU5fj51fP0XL2JrQOGLb4nID73MvnROT4LGiyUNMcLt+/Tvrv/DtWbo3sduL6q/2Dj3VD0xGD l1kTNAzdj+jOA1Jg1SH53Va34KqIAh2n0Ic+3y71eXV+WouCwkYrDiqqxaGZ7KKmPUjeHTLUEhT5Q == root@zw_xx_192\n\n\n\n"
攻击手段:
- 攻击者获取 Redis 访问后,通过修改 Redis 的
dir
和dbfilename
配置,并通过config set
动态修改方式修改 - 然后将自己的公钥写入到目标服务器的
/root/.ssh/authotrized_keys
实现对目标服务器的攻陷。
Redis crackit 攻击的过程与条件:
安全的 Redis
Redis 的密码机制
如何配置
- 配置参数:
requirepass
- 命令方式:
redis-server --requirepass hello_redis
如何访问
- redis-cli -a 参数:
redis-cli -a hello_redis
- auth 命令:在 redis-cli 直接连接后,执行 auth 命令,操作如下:
redis-cli
127.0.0.1:6379> ping
(error) NOAUTH Authentication required. # 提示无权限
127.0.0.1:6379> auth hello_redis # 输入密码
OK
127.0.0.1:6379> ping
PONG
运维建议
- 密码足够复杂(如64个字节以上),因为 Redis 的高性能,简单密码,可短时间内通过暴力破解方式破解
- 如果是主从架构,不要忘记在从节点配置 masterauth(master 的密码)配置,否则会造成主从失败
- auth 是通过明文传输,所以也不是 100% 可靠
伪装危险命令
引入 rename-command
常见的的“危险”命令有:
- keys:若键值较多,存在 Redis 阻塞的可能性
- flushall/flushdb:数据被全部清空
- save:若键值较多,存在 Redis 阻塞的可能性
- debug:如 debug reload 会重启 Redis
- config:config 应交给管理员使用
- shutdown:停止 Redis
如何使用 rename-command:
以 flushall 命令为例
- 在
redis.conf
配置中添加rename-command flushall abcdefghijklmn
- 往后执行
flushall
命令会提示未知命令,但可执行abcdefghijklmn
去执行清空操作
引入 rename-command 带来的问题
- 当修改命令后,常见的第三方库(如:java的jedis)内部操作,无法直接使用相关命令,增加一定的开发和维护成本。
rename-command
不支持动态的config set
,需在配置中设定后,启动。- 如果 AOF 和 RDB 文件包含了 rename-command 之前的命令, Redis 将无法正常工作。
最佳实践
- 对于一些危险的命令(如:flushall),无论内网或外网,均使用
rename-command
配置 - 建议第一次配置 Redis 时,就配置好 rename-command ,因为 rename-command 不支持动态的 config set,也不支持 RDB 和 AOF 文件对历史修改命令的载入。
- 如果涉及主从关系,主从配置应该保持一致性。
防火墙
可通过防火墙限制输入、输出的 IP 或 IP 范围、以及端口或者端口范围。
bind
bind 的理解
- 错误的理解:配置的 bind 认为 Redis 直接接收来自某个网段 IP 的客户端请求。
- 正确的理解:bind 指的是 Redis 与哪个网卡进行绑定。
如 ifconfig 命令获取当前的网卡信息,发现包含三个 IP:
- 内网地址: 10.10.1.192
- 外网地址:220.181.1.123
- 回环地址:127.0.0.1
配置参考如下:
- Redis 如配置了 bind 10.10.1.192,那只有 10.10.1.* 的 IP 段可连接;
- Redis 如配置了 bind 127.0.0.1,那只有本机可连接;
- Redis 如配置了 bind 0.0.0.0,那任何 IP 段都可连接;
- 当然 Redis 也支持绑定多个网卡,如:bind 10.10.1.192 220.181.1.123
运维提示:Redis 3.0 的 bind 默认值是 “”,也就是不限制网卡访问;但是在 Redis 3.2 中,必须配置 bind 0.0.0.0 才可达到该效果
运维建议
- 如果机器有外网 IP,但 Redis 部署给内网使用,建议去掉外网网卡或者使用 bind 配置限制流量从外网进入
- 如果客户端和 Redis 部署在同一台服务器,可使用回环地址:127.0.0.1
- bind 不支持动态的 config set,所以建议第一次配置 Redis 的时候配置好
关于 protected-mode 配置的说明:
- Redis 3.2 提供,默认开启
- 含义:如果那个 Redis 没有配置密码,没有配置 bind,那么只允许来自本机的访问,也就是相当于配置了 bind 127.0.0.1,伪代码如下:
if (protected-mode && !requirepass && !bind) {
Allow only 127.0.0.1,::1 or socket connections
Deny (with the long message ever!) others
}
定时备份数据
- 定时备份能晚会一些数据损失
不使用默认端口
- Redis 默认端口:6379
- 不适用默认端口可减低被入侵的发现可能
一般攻击者会对目标服务器端口进行扫描,比如常见的端口:MySQL的3306等
使用非 root 用户启动
root 权限过大,如 Redis 被攻陷,基本可在当前机器上“为所欲为”。