Redis 生产环境被黑事故

临近午饭点,正值流量高峰期,所有应用突然大量报错 Redis 连接超时、无法获取到连接。

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out
	at redis.clients.jedis.Protocol.process(Protocol.java:86)

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
	at redis.clients.util.Pool.getResource(Pool.java:40)
	at 

同事查看 Redis 监控发现,Redis 进程使用内存一直维持着配置的内存 maxmemeory 高位,本着先止血的原则,决定调高最大内存配置重启,服务短暂正常了几分钟,接着又开始报错。

这里其实是有问题的,内存这几天一直在高位,另外贸然重启很有可能会导致数据丢失。

所有应用都出现问题,大概率是 Redis 服务自身出了问题,直接查看 Redis 日志发现了异常

[1550] 11 Jul 11:27:33.078 * Background saving started by pid 2756
[2756] 11 Jul 11:27:33.078 # Failed opening .rdb for saving: Permission denied
[1550] 11 Jul 11:27:33.178 # Background saving error

怎么会没有权限呢,配置的文件夹权限没有问题,磁盘空间也没有问题。

但是查看快照文件夹的时候,发现了一个名字叫 root 的可疑文件,不会被黑了吧?

接着发现我们的 Redis 服务公网居然可以直接访问,而且没有密码!

使用 netstat 命令和 Redis 的内置命令 CLIENT LIST 查看发现有个海外的公网 IP 在访问。

通过 CLIENT KILL 命令杀掉这个客户端,并且关闭公网访问后服务恢复正常。

事后复盘,之所以开启了公网访问,是因为运维为了打通 ucloud 和阿里云的专线访问,加 ip 白名单的时候子网掩码配置成了 0 (这样相当于所有 ip 都能访问) 😆。

当然,这样暴漏了我们的很多问题

  • 密码不配置
  • 未限制只绑定内网网卡
  • Redis 不隐藏/禁止危险命令 (config | keys | flushdb | flushall...)

Redis 安全攻击文章参考


当时应用里也有相关报错提示快照持久化出问题了。

redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
	at redis.clients.jedis.Protocol.processError(Protocol.java:127)
	at redis.clients.jedis.Protocol.process(Protocol.java:161)
	at redis.clients.jedis.Protocol.read(Protocol.java:215)

我原本以为 Redis 的 RDB 快照持久化是异步的,不会阻塞主线程,其实 Redis 有个 stop-writes-on-bgsave-error 的配置。

By default Redis will stop accepting writes if RDB snapshots are enabled (at least one save point) and the latest background save failed.