pickle存在安全隱患的原因是反序列化時(shí)會(huì)執(zhí)行任意代碼。pickle模塊用于將python對(duì)象轉(zhuǎn)換為字節(jié)流以便存儲(chǔ)或傳輸,但加載不可信數(shù)據(jù)時(shí)可能觸發(fā)惡意指令。例如攻擊者可通過(guò)構(gòu)造特殊對(duì)象,在反序列化時(shí)調(diào)用系統(tǒng)命令。常見(jiàn)風(fēng)險(xiǎn)場(chǎng)景包括網(wǎng)絡(luò)傳輸、緩存機(jī)制及日志配置文件中誤用pickle格式。為安全使用pickle應(yīng)做到:1.僅加載可信來(lái)源的pickle文件;2.避免用其做跨語(yǔ)言通信;3.對(duì)輸入數(shù)據(jù)進(jìn)行簽名驗(yàn)證;4.在沙箱環(huán)境中加載pickle;5.優(yōu)先選用json等更安全的替代格式。總之務(wù)必遵循原則“永遠(yuǎn)不要加載你不信任的數(shù)據(jù)”。
在python中,pickle 是一個(gè)常用的對(duì)象序列化模塊,可以將復(fù)雜的Python對(duì)象轉(zhuǎn)換為字節(jié)流,便于存儲(chǔ)或傳輸。但如果你從不可信的來(lái)源加載了 pickle 數(shù)據(jù),那可能會(huì)帶來(lái)嚴(yán)重的安全隱患。
什么是Pickle序列化?
Pickle 模塊的作用是“把Python對(duì)象變成一串字節(jié)”,這個(gè)過(guò)程叫做序列化。它非常適合用于保存程序運(yùn)行時(shí)的狀態(tài),比如緩存數(shù)據(jù)、保存模型參數(shù)等。使用起來(lái)也非常簡(jiǎn)單:
import pickle data = {"name": "Alice", "age": 30} with open("data.pkl", "wb") as f: pickle.dump(data, f)
讀取的時(shí)候也是一樣方便:
with open("data.pkl", "rb") as f: loaded_data = pickle.load(f)
看起來(lái)很美好,但問(wèn)題就出在反序列化(load)這一步。
立即學(xué)習(xí)“Python免費(fèi)學(xué)習(xí)筆記(深入)”;
Pickle為什么存在安全隱患?
核心問(wèn)題是:pickle 在反序列化時(shí)會(huì)執(zhí)行任意代碼。
它不僅還原數(shù)據(jù),還會(huì)嘗試重建對(duì)象,包括調(diào)用構(gòu)造函數(shù)和自定義的 __reduce__ 方法。這就意味著,攻擊者可以通過(guò)構(gòu)造惡意的 .pkl 文件,在你加載文件時(shí)執(zhí)行任意命令,比如刪除文件、竊取信息甚至遠(yuǎn)程連接。
舉個(gè)簡(jiǎn)單的例子:
import os import pickle class MaliciousData: def __reduce__(self): return (os.system, ("rm -rf /tmp/test",)) mal_data = pickle.dumps(MaliciousData()) # 如果你不小心加載了這個(gè)數(shù)據(jù)…… pickle.loads(mal_data)
一旦執(zhí)行了上面的 pickle.loads,就會(huì)執(zhí)行 rm -rf /tmp/test 命令。這就是所謂的“反序列化漏洞”。
什么場(chǎng)景下容易踩坑?
-
網(wǎng)絡(luò)傳輸中使用了Pickle
有些人為了方便,直接通過(guò)網(wǎng)絡(luò)傳輸 pickle.dumps() 的結(jié)果。如果對(duì)方不可信,或者中間有人篡改數(shù)據(jù)包,就可能觸發(fā)惡意代碼。 -
緩存機(jī)制中用了Pickle文件
比如用 pickle 存儲(chǔ)用戶提交的數(shù)據(jù),之后再加載回來(lái)。如果有攻擊者上傳了一個(gè)惡意構(gòu)造的 .pkl 文件,服務(wù)器加載時(shí)就會(huì)被攻擊。 -
日志或配置文件中誤用了Pickle格式
雖然不常見(jiàn),但如果某些系統(tǒng)組件寫(xiě)入了可被用戶修改的 .pkl 文件,并由高權(quán)限進(jìn)程加載,也可能成為攻擊入口。
如何安全地使用Pickle?
如果你確實(shí)需要使用 pickle,可以考慮以下幾個(gè)建議:
- ? 只加載你自己生成的Pickle文件,避免處理外部輸入。
- ? 不要用Pickle做跨語(yǔ)言通信,它不是通用協(xié)議。
- ? 對(duì)輸入進(jìn)行簽名驗(yàn)證,確保數(shù)據(jù)未被篡改。
- ? 使用沙箱環(huán)境加載Pickle,限制執(zhí)行權(quán)限。
- ? 替代方案優(yōu)先選JSON、YAML、MessagePack等更安全的格式,除非必須保留Python對(duì)象結(jié)構(gòu)。
如果你一定要接收外部的Pickle數(shù)據(jù),可以考慮自己實(shí)現(xiàn)一個(gè)白名單式的反序列化解析器,或者使用像 dill 這樣的庫(kù),雖然它們也不是絕對(duì)安全。
總結(jié)一下
Pickle 很方便,但它不是用來(lái)處理不可信數(shù)據(jù)的工具。只要記住一句話:“永遠(yuǎn)不要加載你不信任的數(shù)據(jù)”,就能避免大多數(shù)問(wèn)題。
基本上就這些。