国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

記一次Redis被攻擊的事件

2019-11-14 15:44:10
字體:
來源:轉載
供稿:網友

最近幾個月非常忙,所以很少有時間寫博客,這幾天終于閑了一些,于是就在整理平時的一些筆記。恰好這幾天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

然后意識到是不是Redis沒有設置密碼訪問,導致產生了這個漏洞被利用和攻擊了。于是自查,發現了如下內容:

RedisCraket

 

 

里邊多了一個名為crackit的字符串,并且db0這個庫是沒有使用了的,現有的數據和邏輯都在db1上,剛打開的時候,db1是空的,上圖是我重新同步過數據之后的結構。

對比烏云報的漏洞的最后一部分:

 

wuyuncrack

這簡直就是一模一樣啊。并且運維那邊發現redis的持久化文件被寫到了authorized_keys文件中:

linux

確認被攻擊之后,于是開始著手修復。之前在開發的時候,其實是有考慮給Redis加訪問密碼的,不知道后來太忙了,竟然給忘了,也想著公司比較小,應該不會被黑之類的,沒想到這次就撞上了。

解決方法

解決方法當然是給Redis加密碼,然后在訪問的時候,設置密碼訪問。

最初,訪問Redis的客戶端我們使用的是ServiceStack.Redis,我之前也寫過幾篇Redis相關的文章。 由于考慮到授權的原因,使用的是2.0版本的dll,在其API中,從簽名看,沒有地方可以設置密碼:

ServiceStack.RedisClient

這個地方只能設置主機名稱和端口號。

于是在使用中,比如下面這個刪除群組的操作,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,這個是商業化版本的,使用中發現,是有限制的,在其下載頁面最下角也有說明:

Redis Limit

每小時只能請求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服務器本身沒有對登錄做限制),也感謝有烏云這么好的一個平臺,能夠及時發現系統的問題和漏洞,避免出現更大的損失。作為一個碼農其實不應該抱有這樣的僥幸心理,就像墨菲定律說的那樣“會出錯的,終將會出錯“ 。最后,希望這篇文章能給大家一個提醒和一些幫助。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 安吉县| 呼玛县| 安顺市| 清河县| 清新县| 牙克石市| 宝丰县| 湖南省| 绥棱县| 泰宁县| 大安市| 广宗县| 宁蒗| 沙湾县| 离岛区| 浦县| 桐城市| 中阳县| 洛阳市| 皋兰县| 龙江县| 高雄县| 滦南县| 进贤县| 和龙市| 中宁县| 铜陵市| 兰考县| 五河县| 拜泉县| 同江市| 曲松县| 灵璧县| 大石桥市| 延庆县| 华安县| 临邑县| 虞城县| 郸城县| 德格县| 广东省|