最近几个月非常忙,所以很少有时间写博客,这几天终于闲了一些,于是就在整理平时的一些笔记。恰好这几天Redis服务器发生了问题,就记录一下。

我司有两款分别是2B和2C的App,类似于阿里旺旺的卖家版和买家版,里面有一个聊天的功能模块。双方可以通过这个功能聊天。内部通讯使用了环信,只是将本地账号和环信账号进行了关联。其他的信息,比如用户基本信息,好友关系,群组关系等存在Redis中,为防止Redis出现问题导致数据丢失(尽管配置了持久化),同时使用消息队列将数据写入SQLServer中进行了冗余。这是一种Redis的典型使用场景,从速度和效率上满足要求。

线上环境一直运行正常,但是在上周日(一个本该休息的日子),领导打电话过来说线上环境的用户登录不了,无法聊天,没有群相关信息。我想估计是Redis出现了问题,让领导不要着急,先让运维看看服务是否还在运行,不行的话,把Redis重启一下,因为之前设置过持久化,数据应该不会丢失。于是继续陪夫人吃饭,看电影。

到了晚上,还是打电话过来说有问题,没办法只有来公司一趟。打开机器用RedisClient连Linux环境上的Redis,发现里面的数据全没了,只有几个新注册的孤零零的用户在里面,我当时惊呆了,以为是运维那边没搞好,是重启的整个服务器而不是重启的Redis,可能是Redis没有及时保存把数据给弄丢了。看到现象之后跟领导电话告知目前的现象和建议的解决方案,在授权下,重新把用户相关数据从SQLServer同步到了Redis中,关键的数据还好没丢失,然后让测试简单测试了一下,一切正常就没有太在意。而且由于Redis是安装在Linux上的,是由运维同事维护的,出问题了我这边也查不了,于是就回去了。

但是事情远没有那么简单,星期一的时候,领导又打电话过来说聊天又不能用了,比较急说要赶紧处理,我说好,于是不紧不慢的收拾好出门去公司。心里非常不爽,前段时间加班太猛,周一周二全公司开发都调休放假的。就我一个开发的来到公司,打开远程又发现Redis里面的数据全没了。于是又从SQLServer把数据同步到了Redis里,然后检查代码,把除了和聊天相关之外的其他逻辑,比如Redis定时同步服务相关的可能会影响到的地方都暂停了。因为前段时间做了一次重构,担心是代码导致数据丢失,搞完了之后就回去了。

然而好景不长,消停了一天没出问题。今天早上过来上班,领导走过来语重心长的说,聊天又登不上了,上去一看,Redis里面的数据又没了。正好运维的同事也在,也就一起找下存在的漏洞和可能的原因。

原因

前几天无意在微博上看到了乌云平台发的一条漏洞信息:

然后意识到是不是Redis没有设置密码访问,导致产生了这个漏洞被利用和攻击了。于是自查,发现了如下内容:

里边多了一个名为crackit的字符串,并且db0这个库是没有使用了的,现有的数据和逻辑都在db1上,刚打开的时候,db1是空的,上图是我重新同步过数据之后的结构。

对比乌云报的漏洞的最后一部分:

这简直就是一模一样啊。并且运维那边发现redis的持久化文件被写到了authorized_keys文件中:

确认被攻击之后,于是开始着手修复。之前在开发的时候,其实是有考虑给Redis加访问密码的,不知道后来太忙了,竟然给忘了,也想着公司比较小,应该不会被黑之类的,没想到这次就撞上了。

解决方法

解决方法当然是给Redis加密码,然后在访问的时候,设置密码访问。

最初,访问Redis的客户端我们使用的是ServiceStack.Redis,我之前也写过几篇Redis相关的文章。 由于考虑到授权的原因,使用的是2.0版本的dll,在其API中,从签名看,没有地方可以设置密码:

这个地方只能设置主机名称和端口号。

于是在使用中,比如下面这个删除群组的操作,RedisHelper类是对ServiceStack.Redis的一个封装类,只需要设置主机和端口号:

public static bool DeleteGroup(string groupId)
{lock (lockDeleteGroup){bool result = true;using (RedisHelper redis = new RedisHelper(HOST, PORT)){var group = redis.GetWhereObj<GroupTable>(GROUPTABLE, x => x.GroupId == groupId);group.Is_Deleted = true;result = redis.Update<GroupTable>(GROUPTABLE, x => x.GroupId == groupId, group);}return result;}
}

后面为了安全考虑,需要给Redis设置个密码,于是下载了最新版本的4.0的ServiceStack.Redis,这个是商业化版本的,使用中发现,是有限制的,在其下载页面最下角也有说明:

每小时只能请求6000次,这显然不能满足要求。除了以上限制之外,在使用过程中也出现过一些相当诡异的问题,比如通过Id查找的时候,其只能在1k条范围内进行查询等等,当然,也有可能是因为使用不正确,考虑到以上原因,加之之前的数据组织和结构设计不合理,于是决定重构。

重构的时候,就直接换了另一个C#客户端,StackExchange.Redis。

private static ConnectionMultiplexer _redis;
private static IDatabase _db;
private static IServer _server;
private static bool needSave = false;
private void Init(string host, int port, string pwd, int database)
{var options = ConfigurationOptions.Parse(host + ":" + port);options.SyncTimeout = int.MaxValue;options.AllowAdmin = true;if (!string.IsNullOrEmpty(pwd)){options.Password = pwd;}if (_redis == null)_redis = ConnectionMultiplexer.Connect(options);if (_server == null)_server = _redis.GetServer(host + ":" + port);if (_db == null)_db = _redis.GetDatabase(database);needSave = false;
}

这里面,可以直接对options对象设置Password属性。于是对该对象进行了包装,后面使用Redis可以这样,在构造函数里边传入PWD即可,比如下面判断用户是否存在的接口:

public static bool HasShopUser(string userName)
{bool hasUser = false;ShopUserEntity userEntity;userEntity = null;using (RedisHelper redis = new RedisHelper(HOST, PORT, PWD)){userEntity = redis.GetShopUserInfo(userName);}if (userEntity != null){hasUser = true;}return hasUser;
}

在替换Redis客户端访问类的时候,顺便对之前Redis里面的数据结构进行了一次重构,经过这次重构,速度提升很明显。于是,于是就直接弄到正式环境然后就把设置密码这个事情给忘记了。

当然,部署有Redis的Linux服务器也按照漏洞建议做了登陆限制和修复。

总结

其实这是一个很低级的错误,访问Redis没有设置密码(当然也可能是Redis所在的Linux服务器本身没有对登录做限制),也感谢有乌云这么好的一个平台,能够及时发现系统的问题和漏洞,避免出现更大的损失。作为一个码农其实不应该抱有这样的侥幸心理,就像墨菲定律说的那样“会出错的,终将会出错“ 。最后,希望这篇文章能给大家一个提醒和一些帮助。

记一次Redis被攻击的事件相关推荐

  1. Spring Boot 监听 Redis Key 失效事件实现定时任务

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:彭超 https://antoniopeng.com 业务场 ...

  2. 悬崖边上的舞者,记7.2生产数据库灾难事件

    悬崖边上的舞者,记7.2生产数据库灾难事件 作者:张子良 版权所有,转载请注明出处 引子:出事了 7月2日是一个难得的大晴天,一段时间以来桂林一直在下雨,一直下,害的我减肥的计划一再的泡汤,因为下雨每 ...

  3. 事件库之Redis自己的事件模型-ae

    2019独角兽企业重金招聘Python工程师标准>>> #Redis自己的事件模型 ae ##1.Redis的事件模型库 大家到网上Google"Redis libeven ...

  4. Redis教程:事件、客户端和服务器

    1 事件 Redis服务器是一个事件驱动程序,服务器需要处理以下两类事情: 文件事件(file event):Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接,而文件事件就是服务 ...

  5. 网线还能这样玩???(哈哈哈,记一次差点被揍事件)

    网线还能这样玩???(哈哈哈,记一次差点被揍事件) 以下是个真实事件,嘿嘿嘿,胆小请勿模仿 某天,我闲的无聊,突然看到了角落里的那两台电脑(瑟瑟发抖),邪恶善良的我决定让他们嘿嘿嘿通过一根网线直接连在 ...

  6. Redis key过期事件监听实现 - 30分钟自动取消未支付订单

    目录 一.前言 二.实现方案分析 三.Redis key过期事件方案实现步骤 3.1 Redis 安装步骤详见 3.2 修改 Redis 配置 3.3 在获取支付链接视图中设置key过期事件 3.4 ...

  7. 【挖矿木马】记一次被挖矿木马攻击的过程(Redis被攻击)

    不会吧,不会吧,不会2020年了还有人中挖矿木马吧. 0x01.事情经过: 关于这台服务器:我有一台阿里云的服务器(不是学生机)专门拿来做项目测试用的,部署好一些我经常需要用的组件后,平常就没怎么管过 ...

  8. windows事件id大全_技术转载 || springboot+redis做过期事件通知业务

    我的业务场景 系统管理员要给维护员分配巡查路口设施的工作,由于路口比较多,管理员不知道哪些路口已经被分配了,况且过了一个时间周期后,所有的路口要再次被巡查. 思路 我建立了一个表,里面是所有路口和是否 ...

  9. redis 能不能监听特定的key失效_Spring boot实现监听Redis key失效事件实现和其它方式...

    1.pom 中添加依赖 org.springframework.boot spring-boot-starter-data-redis 2.定义配置RedisListenerConfig /** * ...

最新文章

  1. Python面试之 is 和 == 的区别
  2. 汉语(普通话)的音素对齐
  3. 【mysql】使用tpcc-mysql进行压力测试
  4. 蒸发器分段设计matlab程序_制冷系统蒸发器过热度控制回路的MATLAB仿真_何煜
  5. 机电传动控制大作业 第一阶段
  6. 癌症世界难题_癌强大的真相被发现了,这4个难题不攻克,癌症难以治愈
  7. python发音1001python发音-1001种玩法 | Python 学习指南资源
  8. 点击出现遮罩层时滚动条会自己回到顶部_浅谈内容型信息流产品的“返回顶部”功能...
  9. 使用el-tree-transfer不显示label的坑
  10. winpe装双系统linux_自制WINPE+MAC安装U盘及双系统存储U盘(增加多系统安装)
  11. Exchange 2010环境部署2
  12. 【随笔】Linux主机简单判断CC攻击的命令
  13. 如何在谷歌地图上标注宾馆饭店矢量点并叠加导出为图片
  14. “21天好习惯”第一期- 11 反爬虫机制详解(3)
  15. Mongodb高级查询Aggregation聚合组件分页
  16. [4G5G专题-114]:部署 - LTE PRACH前导码格式、ZC序列的生成规则与规划
  17. php模式设计之 适配器模式
  18. MYSQL初学者使用指南
  19. 计算机定期备份用什么程序,怎么让电脑定期自动备份文件或文件夹(让你的电脑每天定时自动为你备份重要的文件)...
  20. 【文献笔记】Viewing personalized video clips recommended by TikTok activates default mode network and vent

热门文章

  1. 优秀家长经验分享发言稿——家校合力,共促孩子健康、快乐成长
  2. 梆梆安全亮相网络安全博览会 矢志保护智能生活
  3. 5G丨通讯运营商沃达丰将于7月3日在英国7个城市推出5G服务
  4. 【推荐收藏】C++函数大全
  5. 计算机不能上网 检查路线,电脑上不了网怎么解决?
  6. linux创建xfs文件系统命令,通过案例学习xfs文件系统相关命令
  7. 网络模拟器 eNSP、EVE-NG、GNS3、Packet Tracert
  8. VBS基础篇 - 循环语句(2) - While...Wend
  9. 继电保护整定计算程序简介
  10. JAVA计算机毕业设计作品测评网站Mybatis+源码+数据库+lw文档+系统+调试部署