安全的Redis
2015年11月,全球數(shù)萬個Redis節(jié)點遭受到了攻擊邀跃,所有數(shù)據(jù)都會被清除了霉咨,只有一個叫crackit的鍵存在,這個鍵的值很像一個公鑰拍屑。
數(shù)據(jù)丟失對于很多Redis的開發(fā)者來說是致命的途戒,經(jīng)過相關機構的調查發(fā)現(xiàn),被攻擊的Redis有以下特點:
Redis所在的機器有外網(wǎng)IP
Redis以默認端口6379為啟動端口丽涩,并且是對外網(wǎng)開放的棺滞。
Redis是以root用戶啟動的
Redis沒有設置密碼
Redis的bind設置為0.0.0.0或者""
攻擊者充分利用Redis的dir和dbfilename兩個配置可以利用config set動態(tài)設置,以及RDB持久化的特性矢渊,將自己的公鑰寫入到目標機器的/root/.ssh/authotriezed_keys文件中继准,從而實現(xiàn)了對目標機器的攻陷。
假設機器A是攻擊者的機器(內網(wǎng)IP:10.10.xx.192)矮男,機器B是被攻擊者機器(外網(wǎng)IP:123.16.xx.182)移必,上面部署著一個滿足上述五個特性的Redis,下面我們來模擬整個攻擊過程:
1)首先確認當前(攻擊前)機器A不能通過SSH訪問機器B毡鉴,因為沒有權限崔泵。
2)由于機器B的外網(wǎng)對外開通了Redis的6379端口,所以可以直接連接到Redis上執(zhí)行flushall操作猪瞬,注意此事破壞性已經(jīng)很大了憎瘸。
3)在機器A生成公鑰,并將公鑰保存到一個文件my.pub中陈瘦。
4)將鍵crackit的值設置為公鑰幌甘。
5)將Redis的dir設置為/root/.ssh目錄,dbfilename設置為authorized_keys,執(zhí)行save命令生成RDB文件锅风。此時機器B的/roor/.ssh/authorized_keys包含了攻擊者的公鑰酥诽,之后攻擊者就可以“為所欲為”了。
6)此時機器A再通過SSH協(xié)議訪問機器B皱埠,發(fā)現(xiàn)可以順利登錄肮帐,登錄后可以觀察/root/.ssh/authorized_keys,可以發(fā)現(xiàn)它就是RDB文件边器。
誰也不想自己的Redis以及機器就這樣被攻擊吧训枢?本節(jié)我們來介紹如何讓Redis足夠安全。
Redis的設計目標是一個在內網(wǎng)運行的輕量級高性能鍵值服務饰抒,因為是在內網(wǎng)運行肮砾,所以對于安全方面沒有做太多的工作诀黍,Redis值提供了簡單的密碼機制袋坑,并且沒有做用戶權限的相關劃分。那么眯勾,在日常對于Redis的開發(fā)和運維中要注意哪些方面才能讓Redis服務不僅能提供高效穩(wěn)定的服務枣宫,還能保證在一個足夠安全的網(wǎng)絡環(huán)境下運行呢?下面將從7個方面進行介紹吃环。
-
Redis密碼機制
-
簡單的密碼機制
Redis提供了requirepass配置為Redis提供密碼功能也颤,如果添加這個配置,客戶端就不能通過redis-cli -h {ip} -p {port}來執(zhí)行命令郁轻。例如下面啟動一個密碼為hello_redis-devops的redis:
redis-server --requirepass hello_redis_devpos
此時通過redis-cli執(zhí)行命令會受到?jīng)]有權限的提示:
# redis-cli 127.0.0.1:6379> ping (error) NOAUTH Authentication required.
Redis提供了兩種方式訪問配置了密碼的Redis:
- redis-cli -a參數(shù)翅娶。使用redis-cli連接Redis時,添加-a加密碼的參數(shù)好唯,如果密碼正確就可以正常訪問Redis了竭沫,具體操作如下:
# redis-cli -h 127.0.0.1 -p 6379 -a hello_redis_devops 127.0.0.1:6379> ping PONG
- auth命令。通過redis-cli連接后骑篙,執(zhí)行auth加密碼命令蜕提,如果密碼正確就可以正常訪問訪問Redis了,具體操作如下:
# redis-cli 127.0.0.1:6379> auth hello_redis-devops OK 127.0.0.1:6379> ping PONG
-
運維建議
這種密碼機制能在一定程度上保護Redis的安全靶端,但是在使用requirepass時候要注意以下幾點:
密碼要足夠復雜(64個字節(jié)以上)谎势,因為Redis的性能很高,如果密碼比較單間杨名,完全是可以在一段時間內通過暴力破解來破譯密碼脏榆。
如果是主從結構的Redis,不要忘記在從節(jié)點的配置中加入masterauth(master的密碼)配置台谍,否則會造成主從節(jié)點同步失效须喂。
auth是通過明文進行傳輸?shù)模砸膊皇?00%可靠,如果被攻擊者劫持也相當危險镊折。
-
-
偽裝危險命令
-
引入rename-command
Redis中包含了很多“危險”命令胯府,一旦錯誤使用或者誤操作,后果不堪設想恨胚,例如如下命令:
keys:如果鍵值較多骂因,存在阻塞Redis的可能性。
flushall/flushdb:數(shù)據(jù)全部被清除赃泡。
save:如果鍵值較多寒波,存在阻塞Redis的可能性。
debug:例如debug reload會重啟Redis升熊。
config:config應該交給管理員使用俄烁。
shutdown:停止Redis。
理論上這些命令不應該給普通開發(fā)人員使用级野,那有沒有什么好的方法能夠防止這些危險命令被隨意執(zhí)行呢页屠?Redis提供了rename-conmmand配置解決這個問題。下面直接用一個例子說明rename-command的作用蓖柔。例如當前Redis包含了10000個鍵值對辰企,現(xiàn)使用flushall將全部是數(shù)據(jù)清除:
127.0.0.1:6379> flushall OK `` 例如Redis添加如下配置: `rename-command flushall flushalltest` 那么執(zhí)行flushall命令的話,會收到Redis不認識flushall的錯誤提示况鸣,說明我們成功地使用rename-command對flushall命令做了偽裝:
127.0.0.1:6379> flushall
(error) ERR unknonwn command 'flushall'而如果執(zhí)行flushalltest牢贸,那么就可以實現(xiàn)flushall的功能了,這就是rename-command的作用镐捧,管理員可以對認為比較危險的命令做rename-command處理潜索。
-
沒有免費的午餐
rename-command雖然對Redis的安全有一定幫助,但是天下并沒有免費的午餐懂酱。使用了rename-command時可能會帶來如下麻煩:
管理員要對自己的客戶端進行修改竹习,例如jedis.flushall()操作內部使用的是flushalll命令,如果用rename-command后需要修改為新的命令玩焰,有一定的開發(fā)和維護成本由驹。
rename-command配置不支持config set,所以啟動前一定要確定哪些命令需要使用rename-command昔园。
如果AOF和RDB文件包含了rename-command之前的命令蔓榄,Redis將無法啟動,因為此時它識別不了rename-command之前的命令默刚。
Redis源碼中有一些命令是寫死的甥郑,rename-command可能造成Redis無法正常工作。例如Sentinel節(jié)點在修改配置時直接使用了config命令荤西,如果對config使用rename-command澜搅,會造成Redis Sentinel無法正常工作伍俘。
-
最佳實踐
在使用rename-command的相關配置時,需要注意以下幾點:
對于一些危險的命令(例如flushall)勉躺,不管是內網(wǎng)還是外網(wǎng)癌瘾,一律使用rename-command配置。
建議第一次配置Redis時饵溅,就應該配置rename-command妨退,因為rename-command不支持config set。
如果涉及主從關系蜕企,一定要保持主從節(jié)點配置一致性咬荷,否則存在主從數(shù)據(jù)不一致的可能性。
-
-
防火墻
可以使用防火墻限制輸入和輸出的IP或者IP范圍轻掩、端口或者端口范圍幸乒,在比較成熟的公司都會對有waiwangIP的服務器做一些端口的限制,例如只允許80端口對外開放唇牧。因為一般來說罕扎,開放外網(wǎng)IP的服務器中Web服務器比較多,但通常存儲服務器的端口無序對外開放奋构,防火墻是一個限制外網(wǎng)訪問Redis的必殺技壳影。
-
bind
-
對于bing的錯誤認識
很多開發(fā)者在一開始看到bind這個配置是都是這么認為的:指定Redis只接收來自于某個網(wǎng)段IP的客戶端請求。
但事實上bing指定的是Redis和哪個網(wǎng)卡進行綁定弥臼,和客戶端是什么網(wǎng)段沒有關系。ifconfig命令獲取網(wǎng)卡信息包含了三個IP地址:
內網(wǎng)地址:10.10.xx.192
外網(wǎng)地址:220.181.xx.123
回環(huán)地址:127.0.0.1
如果當前Redis配置了bind 10.10.xx.192根灯,那么Redis訪問只能通過10.10.xx.192這塊網(wǎng)卡進入径缅,通過redis-cli -h 220.181.xx.123 -p 6379和本機redis-cli -h 128.0.0.1 -p 6379都無法連接到Redis。只能通過10.10.xx.192作為redis-cli的參數(shù)烙肺。
bind參數(shù)可以設置多個纳猪,例如下面配置表示當前Redis只接收來自10.10.xx.192和127.0.0.1的網(wǎng)絡流量:
bind 10.10.xx.192 127.0.0.1
運維提示:Redis3.0中bind默認值為"",也就是不限制網(wǎng)卡的訪問桃笙,但是Redis3.2中必須顯示的配置bind 0.0.0.0才可以達到這種效果氏堤。
-
建議
經(jīng)過上面的實驗以及對于bind的認識,可以得出如下結論:
如果機器有外網(wǎng)IP搏明,但是部署的Redis是給內部使用的鼠锈,建議去掉外網(wǎng)網(wǎng)卡或者使用bind配置限制流量從外網(wǎng)進入。
如果客戶端和Redis部署在一臺機器上星著,可以使用回環(huán)地址127.0.0.1购笆。
bind配置不支持config set,所以盡可能在第一次啟動前配置好虚循。
如果當前Redis沒有配置密碼同欠,沒有配置bind样傍,那么只允許來自本機的訪問,也就是相當于配置了bind 127.0.0.1铺遂。
-
-
定期備份數(shù)據(jù)
天有不測風云衫哥,假如有一天Redis真的被攻擊了(清理了數(shù)據(jù),關閉了進程)襟锐,那么定期備份的數(shù)據(jù)能夠在一定程度挽回一些損失炕檩,定期備份持久化數(shù)據(jù)是一個比較好的習慣。
-
不使用默認端口
Redis的默認端口是6379捌斧,不使用默認端口從一定程度上可降低被入侵者發(fā)現(xiàn)的可能性笛质,因為入侵者通常本身也是一些攻擊程序,對目標服務器進行端口掃描捞蚂,例如MySQL的默認端口是3306妇押、Memcache的默認端口11211、Jetty的默認端口8080等都會被設置成攻擊目標姓迅,Redis作為一款較為致知名的NoSQL服務敲霍,6379必然也在端口的掃毛的列表中,雖然不設置默認端口還是有可能被攻擊者入侵丁存,但是能夠在一定程度上降低被攻擊的概率肩杈。
-
使用非root用戶啟動
root用戶作為管理員,權限非常大解寝。如果被入侵者獲取root權限后扩然,就可以在這臺機器以及相關機器上“為所欲為”了。筆者建議在啟動Redis服務的使用使用非root用戶啟動聋伦。事實上許多服務夫偶,例如Resin、Jetty觉增、HBase兵拢、Hadoop都建議使用非root啟動。