謹防持久化+未授權訪問漏洞入侵伺服器 CVE編號找不到,CNVD有一個:CNVD-2015-07557(國家信息安全漏洞共用平臺漏洞編號)。 這是我之前寫過的文章,漏洞成因、影響範圍、POC與對抗方案有詳解: 謹防利用Redis未授權訪問漏洞入侵伺服器 RDB(Redis Database、全量保存 ...
謹防持久化+未授權訪問漏洞入侵伺服器
CVE編號找不到,CNVD有一個:CNVD-2015-07557(國家信息安全漏洞共用平臺漏洞編號)。
這是我之前寫過的文章,漏洞成因、影響範圍、POC與對抗方案有詳解:
謹防利用Redis未授權訪問漏洞入侵伺服器
RDB(Redis Database、全量保存,預設方式)
- 極簡概括:通過符合單位時間數據被修改的量作為觸發,或手動觸發,把某一時刻的全部數據寫到磁碟。
- 現象:編譯安裝完Redis後啟動,預設會在根目錄(這預設配置地址得吐槽)下生成一個dump.rdb文件。
- 會被自動觸發的情形:
- 配置設置。
- 關閉Redis服務。
- Flashall命令。
- 相關配置:從6.2.0開始有差異:
6.2.0之前
save 900 1 15分鐘至少有1個值被改動,這是避免備份數據與記憶體數據長期不一致的兜底策略。
save 300 10 5分鐘至少有10個值被改動,中庸策略。
save 60 10000 1分鐘至少有1萬個值被改動,避免備份數據與記憶體數據短時間大量不一致的策略。
6.2.0之後,這意味著某些場景,需要改變配置。
save 3600 1
save 300 100
save 60 10000
這種東西怎麼配,若數據要緊,時間就配置的少一點,若要求性能,對數據丟失有容忍度,那就按照預設配置,或加大時間配置。
若要修改rdb文件存放位置和名稱
dir 自定義路徑
dbfilename 自定義文件名.rdb
其它配置:
stop-writes-on-bgsave-error yes
用於在BGSAVE操作出現錯誤時Redis的行為。當這個配置選項被設置為yes時,如果後臺保存操作BGSAVE失敗,Redis將停止接受寫操作,以防止數據丟失。這樣做可以確保數據的完整性,因為在無法完成後臺保存操作時,寫入新數據可能會導致數據不一致或丟失。
當stop-writes-on-bgsave-error被設置為no時,Redis在後臺保存操作失敗時仍然會繼續接受寫操作。這可能會導致數據不一致或丟失,但也可以確保寫操作的連續性。
rdbcompression yes
指定Redis在執行RDB時是否啟用LZF演算法壓縮。
rdbchecksum yes
用於指定在執行RDB(Redis Database)持久化時是否對數據進行校驗和檢查,會有10%的性能消耗。
rdb-del-sync-files no
在沒有持久性的實例中刪除複製使用的RDB文件。
- redis/bin/redis-check-rdb,可檢測rdb文件是否存壞,並修複。
RDB同步持久化與非同步非阻塞持久化
- save(不推薦用):執行期間會阻塞其它命令(意味著臨時停止服務)直到執行完畢,不適合大量請求場景,由於是直接執行,性能比bgsave略高。
- bgsave:會fork一個子進程去處理備份,非同步執行期間不會阻塞其它命令,但是若數據資源相當龐大,仍舊會拉低Redis的性能。
- lastsave:使用lastsave命令,可以查看最後一次執行RDB的時間,對於Redis運維還是有幫助的。
- 註意:在持久化時,需要考慮數據量的大小,與磁碟大小,避免記憶體或者磁碟不足讓服務夯住的情況發生。
- fork: 在Unix/Linux系統中用來創建一個新的子進程的操作。在調用fork() 後,操作系統會複製當前進程的所有內容(包括記憶體數據、堆棧等)到新的子進程中,從而創建一個完全獨立的子進程,而子進程擁有獨立的記憶體空間和進程 ID。
RDB恢複數據
- 註意:由於Redis RDB是全量備份,所以不會像MySQL binlog那種,可以恢復部分數據。也不是像MySQL redo log那種接近實時的備份,RDB備份有間隙,所以就算通過文件恢復,也可能丟失部分數據。
- 如果誤刪了數據:其它節點(如MySQL)又沒有備份,可以利用這個間隙,立即把rdb文件備份,防止觸發redis同步功能覆蓋原數據,把之前持久化的數據整沒了,然後停止Redis(一定要在Redis停止之前備份,利用Redis命令停止Redis也會觸發一次RDB持久化,利用操作系統命令幹掉進程則不會),接著把持久化名字改過來,隨後啟動Redis。
- 預設處理方式:Redis在啟動時會讀取配置,所以RDB文件不需要手動導入,Redis會直接讀取裡面的數據。
- 優點:由於RDB文件具有緊湊的單一文件,所以可以方便的被異地備份,常用的容災手段。
禁用RDB
修改配置文件:清除未被註釋的save項,改為一個save ""
。
AOF(Append Only File、追加寫,增量保存)
- 極簡概括:和RDB是併列關係,將Redis伺服器執行的寫命令追加到一個文件的末尾,由於備份和執行不是實時的原子性操作,所以仍舊有丟失的可能(Redis存在重點是快速用於組件間通信,而不是持久化存儲)。
- 誤區:這裡的only單詞很多餘,有only不代表RDB模式不能被同時啟用。
- 存在意義:
- 畢竟是主流的資料庫,所以要在持久化上利用多備份機製做到位。
- AOF彌補了RDB備份時間間隙(最後一次備份~當前時間未保存)的問題。
- AOF彌補了RDB備份時產生大量磁碟IO的情況發生。
- 配置
找到redis.conf
appendonly no 改為yes
配置持久化模式
appendfsync everysec/always/no
always:每次寫操作,都進行一次追加,最安全但性能最差。
everysec:預設值,每秒進行一次追加,最多丟失一秒鐘的數據。
no:讓操作系統來處理數據同步,由操作系統自行決定何時將數據刷新到磁碟。
三者從上到下性能依次提升,高可用依次降低。
配置保存路徑,Redis7新配置,若低版本沒有,就和RDB目錄一個位置
appenddirname 'appendonlydir'
配置文件名稱
appendfilename "appendonly.aof"
Redis7針對aof文件做了拆分
appendonly.aof.base:基本文件,在壓縮文件時,會將壓縮後的最小指令集保留在此當中。
appendonly.aof.incr:增量文件,該文件存儲對基本AOF文件進行的增量更改。
appendonly.aof.manifest:清單文件,該文件可能與管理和跟蹤AOF文件的狀態或元數據。
備份壓縮相關配置,下文有講
上次重寫之後的增長百分比,這裡預設為100
auto-aof-rewrite-percentage 100
表示aof文件超過64MB。
auto-aof-rewrite-min-size 64mb
雜項配置
no-appendfsync-on-rewrite no
這個配置指示Redis如何將數據寫入磁碟,設置為no表示Redis在重寫時不會改變其關於appendfsync設置的行為。
AOF恢複數據
- 常規情況下:aof備份文件恢複數據是自動的,不需要手動操作。
- 若手動備份文件的方式恢復:若對aof文件做了更名用於多文件備份,恢復時需要改為配置文件中的名稱,然後重啟,即可恢復aof文件中的數據。
- 註意:由於flushall也是寫操作,所以執行它有也會同步aof文件,但是由於aof是增量備份,所以在aof文件中刪除flushall字眼,然後重啟,就能恢複數據。
AOF破損修複與檢測
redis-check-aof 是專門用於檢測與修複aof文件的工具,在redis-cli同級目錄。
檢測,看到AOF is valid說明文件無問題:
./redis-check-aof ../appendonly.aof
AOF analyzed: size=131, ok_up_to=131, diff=0
AOF is valid
但是由於斷電,進程被強制終止,或其它原因導致的文件損壞,可以添加 --fix 去修複。
模擬文件損壞,編輯文件後隨意載入點東西
vim ../appendonly.aof
重啟redis服務,發現redis服務起不來了(配置有服務,下文有講)
service redis restart
修複,看見Successfully字眼,說明修複成功,若是redis7,請操作appendonly.aof.incr增量文件
./redis-check-aof --fix ../appendonly.aof
0x 83: Expected prefix '*', got: 'a'
AOF analyzed: size=139, ok_up_to=131, diff=8
This will shrink the AOF from 139 bytes, with 8 bytes, to 131 bytes
Continue? [y/N]: y
Successfully truncated AOF
啟動redis
service redis start
AOF備份壓縮
- 簡單概括:由於寫命令的增加,AOF文件越來越大,恢復速度也會隨之增加,因此Redis新增了重寫機制,當AOF超過所設定的最大值時,Redis就會自動啟動文件壓縮,只保留可以恢複數據的最小有效指令集,或使用bgrewriteaof來進行壓縮。
- 核心原理:原先set a 1,再執行set a 2,一直到set a 10,初始的aof記錄方式是記錄10條備份,而壓縮只需要記錄1條set a 10,這樣用於減小文件,也用於快速恢複數據,這就是最小有效的指令集。但是一開始就這樣做,意味著時間換空間(更多的計算),會降低aof的性能。
- 自動觸發(需同時滿足兩個配置文件中的條件):
- auto-aof-rewrite-percentage 100:上次重寫之後的增長百分比,這裡預設為100。
- auto-aof-rewrite-min-size 64mb:表示aof文件超過64MB。
- 手動觸發:命令行執行bgrewriteaof命令。
雙備份模式
上文有講,預設開啟的RDB和手動開啟AOF,不會互相影響,兩者是併列關係。
但是有備份粒度更小的AOF,redis啟動時,就不會載入RDB。除非在配置文件中配置aof-use-rdb-preamble yes(實測這個配置yes或no不影響AOF+RDB的同時備份,版本5.0.9)。
這個配置值的意義是:用於控制是否在AOF文件的開頭使用RDB文件的格式。當設置為yes時,Redis在AOF文件的開頭會添加一個RDB文件的內容,以便在重啟時快速載入數據,提高啟動速度和恢復能力。
純緩存模式
- RDB:配置save ‘’
- AOF:配置appendonly no
- 註意:經過實測,仍舊可以使用bgsave或save生成rdb文件,或bgrewriteaof生成aof文件。
擴展,Redis服務編寫
或許你們好奇redis的啟動、關閉、重啟、狀態查看,上文用的service命令,其實是利用bash shell做的,如下:
touch /etc/init.d/redis
chmod +x /etc/init.d/redis
chkconfig redis on,或 systemctl enable redis.service
vim /etc/init.d/redis
#! /bin/bash
REDISPORT=6379
EXEC=/usr/local/redis/bin/redis-server
REDIS_CLI=/usr/local/redis/bin/redis-cli
PIDFILE=/var/run/redis.pid
CONF="/usr/local/redis/etc/redis.conf"
case "$1" in
start)
if [ -f "$PIDFILE" ]; then
echo "$PIDFILE PID文件已存在,進程已在運行或崩潰"
else
echo -n "正在啟動Redis..."
$EXEC $CONF
if [ "$?"="0" ]; then
echo "啟動成功"
else
echo "啟動失敗"
fi
fi
;;
stop)
if [ ! -f "$PIDFILE" ]; then
echo "$PIDFILE PID文件不存在,沒有被運行"
else
PID=$(cat $PIDFILE)
echo "正在關閉Redis"
$REDIS_CLI -p $REDISPORT shutdown
if [ "$?"="0" ]; then
echo "關閉成功"
else
echo "關閉失敗"
fi
fi
;;
restart)
${0} stop
${0} start
;;
kill)
echo "強制終止Redis進程"
killall redis-server
if [ "$?"="0" ]; then
echo "終止成功"
else
echo "終止失敗"
fi
;;
status)
if [ -f "$PIDFILE" ]; then
echo "Redis正在運行"
else
echo "Redis已停止"
fi
;;
*)
echo "命令出錯,只能執行service redis start、stop、restart、status、kill" >&2
exit 1
esac