


摘要:Jinja2 模板的應用使得網站代碼結構清晰,耦合度降低,開發、維護、更新都更容易。該文通過采用不同類型的傳參對Jinja2 模板的安全性進行了測試,并在測試中發現了一些安全性問題,通過實踐,給出了相應的安全防范措施,供同行人員參考。
關鍵詞:Flask;安全性;Jinja2模板
中圖分類號:TP311? ? ?文獻標識碼:A
文章編號:1009-3044(2022)27-0073-03
開放科學(資源服務)標識碼(OSID):
本文所涉及的Jinja2模板本質即Python腳本文件,在大型項目中,視圖函數把業務邏輯和展現內容集成在一起,使得代碼更為復雜,維護成本也更高。使用模板讓視圖函數只進行業務邏輯方面的業務邏輯和數據處理,視圖函數的處理后的數據結果發送到模板進行展示,讓代碼結構清晰,耦合度大幅降低,開發、維護、更新等成本都大幅降低[1]。
1 Jinja2模板簡介
該Python模板文件中包含響應文本,用占位符“{{ }}”標志動態變量位置,模板引擎需要從腳本中標志的動態變量位置獲取外部某個具體的值。使用實際的值替換變量占位符的位置,得到最終的字符串,該工作過程為“渲染”。本文講解的Jinja2模板就是Flask用來進行渲染的模板引擎[2]。
Jinja2模板是一個廣泛應用的Python模板引擎,該模板由Python語言實現,其設計思路源于Django的模板引擎,并擴展了Django模板語法和其一系列強大的功能,是Flask框架的內置模板,Flask框架下的render template函數封裝了Jinja2模板引擎,該函數的第一個參數是文件名(如index.html),后面的參數都是鍵值對,表示模板中變量對應的真實值,使用占位符{{}}來表示變量,這里{{}}成為變量代碼塊,render template函數根據后面傳入的參數,對index.html進行渲染[3]。
2 Jinja2模板安全性測試準備
2.1測試環境搭建
測試系統是安全性檢測的前置條件,測試環境搭建本著真實、無毒、獨立、可復用、前沿、干凈、簡潔、實用等原則[4],本文Jinja2模板安全性測試環境搭建操作系統采用Windows10專業版,使用Visual Studio Code編程軟件 ,使用Python版本為Python3.9的編程語言,安裝flask框架(內含jinja2模板)。
項目部分基本源代碼如圖1所示。
2.2安全性測試方案
訪問本地環境:http://127.0.0.1:5000/ ,在URL中使用GET方式傳參,“?name=xiaoyi”,頁面得到正確的預期響應,回顯為“hello,xiaoyi”,整個請求與響應過程分析如圖2。
(1)用戶通過瀏覽器提交請求給服務器,Web服務器將請求解包后發給App;
(2)App接收到請求后,通過指定route找到給定的視圖函數,然后視圖函數處理、渲染后,返回一個響應response;
(3)App將響應返回給服務器的Web服務;
(4)服務器將響應返回給瀏覽器,瀏覽器展示出來給用戶瀏覽。
3 Jinja2模板安全性測試
3.1非預期傳參測試
功能性測試是系統處理了正常用戶請求的過程,下面輸入非預期的代碼進行測試。輸入內容為:{{7*9}},傳遞到參數進行執行,結果如圖3所示:
此時的后臺代碼執行了7*9,得到運算結果63,所以此時這里就存在安全性問題。接下來進一步構造惡意代碼嘗試進行遠程命令執行。
3.2構造代碼實現遠程RCE原理
在Python中一切皆是對象,因此很多的基礎類都是object類的子類中,想要調用這些類中的方法就需要先通過object類,這樣就可以利用子類(這里以str類為例子)來調用父類object類,再利用object類調用其子類os類,從而實現遠程RCE(遠程命令執行)[5],整個過程如圖4所示。
3.3 構造代碼實現遠程RCE
構造惡意碼的具體步驟具體如下:
就是給定一個變量,這個變量可以是int型、str型、bool型、數組、元組、字典、集合等可以識別類型,也可是未定義的類型,從這個變量通過.__class__獲取其參數類型,如:
輸入:'aa'.__class__ ,返回為class
再通過__base__返回它的基類(也稱父類),如:
輸入:'aa'.__class__.__base__ ,返回為class
再通過__subclasses__()查詢object類中所有子類,并查詢到想要用的類的具體位置,本文中以調用os._wrap_close子類為例,輸入:'aa'.__class__.__base__.__subclasses__()[134],結果如圖5所示。
在Python中所有的類都要經過初始化才能使用,也就是默認調用__init__,因此我們在使用類之前也要調用__init__,通過使用__globals__讀出當前的環境變量,輸入:{{'aa'.__class__.__base__.__subclasses__()[134].__init__.__globals__}},得到結果如圖6所示。
顯示當前位于模塊os.py中,在該模塊中,找到popen方法,進行系統命令執行,輸入{{'aa'.__class__.__base__.__subclasses__()[134].__init__.__globals__['popen']('dir').read()}},實現了遠程命令執行,結果如圖8所示:
4 Jinja2模板安全防護建議
4.1防護思路與方法
針對上面漏洞的防護,思路和其他的注入防御類似,這里對特殊字符自定義黑名單數組blacklist,在獲取用戶輸入的內容后,檢測輸入內容是否為字符串,再將用戶輸入的字符串中的字符逐一與blacklist數組中每一個值比較,如若檢測到用戶輸入中存在敏感字符,則提醒用戶規范輸入,結束程序,反之,如果安全則傳入模板,進行渲染,整體應用到Python代碼中,實現代碼具體如圖8所示:
4.2 防護代碼安全性測試
對上面防護后代碼進行安全性測試,在前端瀏覽器傳入“{}”,返回響應如圖9所示,整體測試結果如表1。
根據響應結果分析,用戶輸入的特殊符號被檢測到存在敏感字符,給用戶友好提示,并終止程序運行,用戶安全輸入信息,經過模板正常渲染回顯,功能不受影響,從而確保了服務器及數據的安全,是有效的防護措施。
5 總結
本文通過環境搭建、傳參測試,發現了Jinja2模板存在的安全性問題,主要是由于開發人員信任了用戶的輸入,未對用戶輸入進行審查而導致的,引發了用戶可以通過輸入惡意代碼實現遠程RCE,讀取服務器內重要信息,甚至獲取到服務器的權限。作者對存在的問題進行了系統地分析,制訂了問題解決方案,設計了安全編碼。經過測試,程序功能正常,能有效防護用戶的惡意輸入,突顯了安全編碼的重要性。
參考文獻:
[1] 劉丹,李志軍,朱書村.基于云端服務檢測設備的虛擬控制面板開發[J].吉林大學學報(信息科學版),2021,39(4):463-469.
[2] 任丹,侯英姿,王方雄,等.基于Flask和Vue的AIS數據分析系統設計與開發[J].軟件,2019,40(10):111-114,120.
[3] 曾思亮.基于Flask框架的微博用戶分類及推薦系統的實現[D].廈門:廈門大學,2017.
[4] 石春宏.Addslashes函數安全性分析[J].電腦知識與技術,2018,14(33):46,54.
[5] 石春宏.淺議ARP攻擊及其防御[J].電腦知識與技術,2016,12(30):26-27.
【通聯編輯:梁書】