redis是一個key-value型資料庫,資訊以鍵對應值的關係儲存在記憶體中,比memcache較大的優勢就在於其資料結構的多樣性。
說它不算一個真正意義上的資料庫,因為redis是主要把資料存放區在記憶體中(當然可以把其儲存至硬碟上,這也是寫shell的必要條件之一),其“緩衝”的性質遠大於其“資料存放區”的性質,其中資料的正刪改查也只是像變數操作一樣簡單。而mongodb卻是一個“儲存資料”的系統,增刪改查資料的時候有“與或非”條件,查詢資料的方式也能像SQL資料庫一樣靈活,這是redis所不具備的。
所以在我的項目中,redis作為session、任務隊列的儲存空間,而mongodb作為資料(包括使用者資訊等)的儲存空間。
進入正題,昨天看到freebuf上已經說了redis可能造成的安全問題,提到了寫檔案,那麼我在這裡把方法說明一下吧。
redis安裝完成以後有自己的命令列,也就是redis-cli,其中包含的命令可以在:http://redis.io/commands 進行查閱。各個用戶端基本也就是依照這個命令去增刪改查。
之前說了redis的資料主要儲存在記憶體中,當與memcache不同之處在於,我們可以隨時執行“save”命令將當前redis的資料儲存到硬碟上,另外redis也會根據配置自動儲存資料到硬碟上。
這不得不說到redis的持久化運作方案 http://redis.io/topics/persistence ,其中說到的一個RDB,一個AOF。RDB更像一個Database Backup檔案,而AOF是一個log記錄檔。我們可以設定讓redis再指定時間、指定更改次數時進行備份,產生RDB檔案;而設定AOF,可以在操作或時間過程後將“日誌”寫入一個檔案的最末,當操作越來越多,則AOF檔案越來越大。
二者是相輔相成的,通過二者的配合我們能夠穩定地持久地將資料存放區於伺服器上。
利用redis寫webshell
而我們就是利用這些儲存資料的操作,來進行任意檔案寫入。
redis的配置中,有幾個關鍵項目:
dir,指定的是redis的“工作路徑”,之後產生的RDB和AOF檔案都會儲存在這裡。
dbfilename,RDB檔案名稱,預設為“dump.rdb”
appendonly,是否開啟AOF
appendfilename,AOF檔案名稱,預設為“appendonly.aof”
appendfsync,AOF備份方式:always、everysec、no
經過我的研究發現,我們可以將dir設定為一個目錄a,而dbfilename為檔案名稱b,再執行save或bgsave,則我們就可以寫入一個路徑為a/b的任意檔案:
當我們獲得了一個redis控制台,我們可以調用config set/get等命令對redis的部分配置進行修改。
而恰好的是,我們可以通過config set來更改dir和dbfilename。也就是說我們可以不用修改redis.conf,也不用重啟redis服務就可以寫入任意檔案:
config set dir /home/wwwroot/default/
config set dbfilename redis.php
set webshell “<?php phpinfo(); ?>“
save
當我們隨便set一個變數webshell的值為”<?php phpinfo(); ?>”後,即可對伺服器進行getshell。可見已寫入:
匯出的RDB實際上是一個二進位檔案,但因為其中包含<?php phpinfo(); ?>,所以被解析了:
在前圖中,我們可以看到其實還產生了一個appendonly.aof,這個檔案名稱能不能自訂呢?可惜的是,appendfilename的值並不能使用config set命令定義:
但僅有的一個dbfilename已經足夠了。
所以,以後如果掃到redis未授權訪問,先別急著提交烏雲。看看伺服器有沒有web服務,如果有,不妨試試能不能拿下webshell。
Mongodb與Redis應用指標對比
MongoDB和Redis都是NoSQL,採用結構型資料存放區。二者在使用情境中,存在一定的區別,這也主要由於
二者在記憶體映射的處理過程,持久化的處理方法不同。MongoDB建議叢集部署,更多的考慮到叢集方案,Redis
更偏重於進程順序寫入,雖然支援叢集,也僅限於主-從模式。
| 指標 |
MongoDB(v2.4.9) |
Redis(v2.4.17) |
比較說明 |
| 實現語言 |
C++ |
C/C++ |
- |
| 協議 |
BSON、自訂二進位 |
類Telnet |
- |
| 效能 |
依賴記憶體,TPS較高 |
依賴記憶體,TPS非常高 |
Redis優於MongoDB |
| 可操作性 |
豐富的資料表達、索引;最類似於關聯式資料庫,支援豐富的查詢語言 |
資料豐富,較少的IO |
MongoDB優於Redis |
| 記憶體及儲存 |
適合大資料量儲存,依賴系統虛擬記憶體管理,採用鏡像檔案儲存;記憶體佔有率比較高,官方建議獨立部署在64位系統(32位有最大2.5G檔案限制,64位沒有改限制) |
Redis2.0後增加虛擬記憶體特性,突破實體記憶體限制;資料可以設定時效性,類似於memcache |
不同的應用角度看,各有優勢 |
| 可用性 |
支援master-slave,replicaset(內部採用paxos選舉演算法,自動故障恢複),auto sharding機制,對用戶端屏蔽了容錯移轉和切分機制 |
依賴用戶端來實現分布式讀寫;主從複製時,每次從節點重新串連主節點都要依賴整個快照,無差異複寫;不支援自動sharding,需要依賴程式設定一致hash機制 |
MongoDB優於Redis;單點問題上,MongoDB應用簡單,相對使用者透明,Redis比較複雜,需要用戶端主動解決。(MongoDB一般會使用replica sets和sharding功能結合,replica sets側重高可用性及高可靠性,而sharding側重於效能、易擴充) |
| 可靠性 |
從1.8版本後,採用binlog方式(MySQL同樣採用該方式)支援持久化,增加可靠性 |
依賴快照進行持久化;AOF增強可靠性;增強可靠性的同時,影響訪問效能 |
MongoDB優於Redis |
| 一致性 |
不支援事物,靠用戶端自身保證 |
支援事物,比較弱,僅能保證事物中的操作按順序執行 |
Redis優於MongoDB |
| 資料分析 |
內建資料分析功能(mapreduce) |
不支援 |
MongoDB優於Redis |
| 應用情境 |
海量資料的訪問效率提升 |
較小資料量的效能及運算 |
MongoDB優於Redis |
Redis、Memcached與 MongoDB三者的區別
如果簡單地比較Redis與Memcached的區別,大多數都會得到以下觀點:
1 Redis不僅僅支援簡單的k/v類型的資料,同時還提供list,set,hash等資料結構的儲存。
2 Redis支援資料的備份,即master-slave模式的資料備份。
3 Redis支援資料的持久化,可以將記憶體中的資料保持在磁碟中,重啟的時候可以再次載入進行使用。
在Redis中,並不是所有的資料都一直儲存在記憶體中的。這是和Memcached相比一個最大的區別(我個人是這麼認為的)。
Redis只會緩衝所有的key的資訊,如果Redis發現記憶體的使用量超過了某一個閥值,將觸發swap的操作,Redis根據“swappability = age*log(size_in_memory)”計算出哪些key對應的value需要swap到磁碟。然後再將這些key對應的value持久化到磁碟中,同時在記憶體中清除。這種特性使得Redis可以保持超過其機器本身記憶體大小的資料。當然,機器本身的記憶體必須要能夠保持所有的key,畢竟這些資料是不會進行swap操作的。
同時由於Redis將記憶體中的資料swap到磁碟中的時候,提供服務的主線程和進行swap操作的子線程會共用這部分記憶體,所以如果更新需要swap的資料,Redis將阻塞這個操作,直到子線程完成swap操作後才可以進行修改。
可以參考使用Redis特有記憶體模型前後的情況對比:
VM off: 300k keys, 4096 bytes values: 1.3G used
VM on: 300k keys, 4096 bytes values: 73M used
VM off: 1 million keys, 256 bytes values: 430.12M used
VM on: 1 million keys, 256 bytes values: 160.09M used
VM on: 1 million keys, values as large as you want, still: 160.09M used
當從Redis中讀取資料的時候,如果讀取的key對應的value不在記憶體中,那麼Redis就需要從swap檔案中載入相應資料,然後再返回給請求方。這裡就存在一個I/O線程池的問題。在預設的情況下,Redis會出現阻塞,即完成所有的swap檔案載入後才會相應。這種策略在用戶端的數量較小,進行大量操作的時候比較合適。但是如果將Redis應用在一個大型的網站應用程式程式中,這顯然是無法滿足大並發的情況的。所以Redis運行我們設定I/O線程池的大小,對需要從swap檔案中載入相應資料的讀取請求進行並行作業,減少阻塞的時間。
redis、memcache、mongoDB 對比
從以下幾個維度,對redis、memcache、mongoDB 做了對比,歡迎拍磚
1、效能
都比較高,效能對我們來說應該都不是瓶頸
總體來講,TPS方面redis和memcache差不多,要大於mongodb
2、操作的便利性
memcache資料結構單一
redis豐富一些,資料操作方面,redis更好一些,較少的網路IO次數
mongodb支援豐富的資料表達,索引,最類似關係型資料庫,支援的查詢語言非常豐富
3、記憶體空間的大小和資料量的大小
redis在2.0版本後增加了自己的VM特性,突破實體記憶體的限制;可以對key value設定到期時間(類似memcache)
memcache可以修改最大可用記憶體,採用LRU演算法
mongoDB適合大資料量的儲存,依賴作業系統VM做記憶體管理,吃記憶體也比較厲害,服務不要和別的服務在一起
4、可用性(單點問題)
對於單點問題,
redis,依賴用戶端來實現分布式讀寫;主從複製時,每次從節點重新串連主節點都要依賴整個快照,無差異複寫,因效能和效率問題,
所以單點問題比較複雜;不支援自動sharding,需要依賴程式設定一致hash 機制。
一種替代方案是,不用redis本身的複製機制,採用自己做主動複製(多份儲存),或者改成差異複寫的方式(需要自己實現),一致性問題和效能的權衡
Memcache本身沒有資料冗餘機制,也沒必要;對於故障預防,採用依賴成熟的hash或者環狀的演算法,解決單點故障引起的抖動問題。
mongoDB支援master-slave,replicaset(內部採用paxos選舉演算法,自動故障恢複),auto sharding機制,對用戶端屏蔽了容錯移轉和切分機制。
5、可靠性(持久化)
對於資料持久化和資料恢複,
redis支援(快照、AOF):依賴快照進行持久化,aof增強了可靠性的同時,對效能有所影響
memcache不支援,通常用在做緩衝,提升效能;
MongoDB從1.8版本開始採用binlog方式支援持久化的可靠性
6、資料一致性(事務支援)
Memcache 在並發情境下,用cas保證一致性
redis事務支援比較弱,只能保證事務中的每個操作連續執行
mongoDB不支援事務
7、資料分析
mongoDB內建了資料分析的功能(mapreduce),其他不支援
8、應用情境
redis:資料量較小的更效能操作和運算上
memcache:用於在動態系統中減少資料庫負載,提升效能;做緩衝,提高效能(適合讀多寫少,對於資料量比較大,可以採用sharding)
MongoDB:主要解決海量資料的訪問效率問題