PHP?中的?RASP?實現(xiàn)流程分析
一、什么是 RASP
RASP 全稱是 Runtime Application self-protection,即運行時應用自我保護,這是一種嵌入到應用程序內(nèi)部,實時檢測來自外部的請求、輸入的技術。PHP 的 RASP 是通過 PHP 拓展的形式嵌入到PHP 的解釋器中。
RASP(Runtime Application self-protection)是一種在運行時檢測攻擊并且進行自我保護的一種技術。早在2012年,Gartner就開始關注RASP,惠普、WhiteHat Security等多家國外安全公司陸續(xù)推出RASP產(chǎn)品,時至今日,惠普企業(yè)的軟件部門出售給了Micro Focus,RASP產(chǎn)品Application Defender隨之易主。而在國內(nèi),去年知道創(chuàng)宇KCon大會兵器譜展示了JavaRASP,前一段時間,百度開源了OpenRASP,去年年底,360的0kee團隊開始測試Skywolf,雖然沒有看到源碼和文檔,但它的設計思路或許跟RASP類似。而商業(yè)化的RASP產(chǎn)品有OneAPM的OneRASP和青藤云的自適應安全產(chǎn)品。在國內(nèi),這兩家做商業(yè)化RASP產(chǎn)品做得比較早。
二、PHP 拓展簡介
PHP 在不同的環(huán)境下有不同的工作模式,常見的有:命令行下的單進程模式和 Apache 環(huán)境下的多進程或者多線程模式。但不管是哪種模式下,都需要執(zhí)行以下幾個流程:
圖1 單進程拓展執(zhí)行流程
單進程模式下整個 PHP 的生命周期為:
圖2 單進程生命周期
多進程模式下的生命周期:
圖3 多進程生命周期
多進程下每個進程只執(zhí)行一次模塊初始化和模塊關閉,會不斷執(zhí)行請求初始化-處理請求-請求關閉的過程。多線程模式下類似,只是處理請求的是線程。
因此我們可以在模塊初始化(MINIT)或者請求初始化(RINIT)階段 hook,這樣每次處理請求的就是我們的業(yè)務邏輯函數(shù),可以在我們的業(yè)務邏輯函數(shù)中對輸入、或者請求進行監(jiān)測,判斷出異常后即可上報風險。
三、PHP 的 HOOK 實現(xiàn)
想要了解 hook 的方式,需要先看一下PHP對腳本的處理流程。
PHP 對腳本進行詞法分析和語分析后會生成 OPArray,也就是 OPCode 的數(shù)組,每個 OPCode 都代表一種不同的操作,名稱類似下面這種:
ZEND_ADD:執(zhí)行兩個操作數(shù)的算術加法操作;
ZEND_EXIT:退出PHP執(zhí)行;
Zend VM中則存在一個主分支循環(huán)(while(1)死循環(huán)),只有當執(zhí)行的 opcode 的 handler 的返回值是1(ZEND_VM_RETURN())時,這個循環(huán)才會結束,所以編譯器會為每個 PHP 腳本在最后添加一個 RETURN 的 OPCode。
以 ZEND_ADD 這個 opcode 為例,這個結構體里包含有兩個操作數(shù)(op1和op2)、handler(函數(shù)指針)、result(運算后的結果)。Zend VM 會根據(jù)兩個操作數(shù)的類型,找到對應的handler,在源碼中對 ZEND_ADD 這個 opcode 的 handler 定義如下:
ZEND_VM_HANDLER(1, ZEND_ADD, CONST|TMP|VAR|CV, CONST|TMP|VAR|CV) { USE_OPLINE zend_free_op free_op1, free_op2; SAVE_OPLINE(); fast_add_function(&EX_T(opline->result.var).tmp_var, GET_OP1_ZVAL_PTR(BP_VAR_R), GET_OP2_ZVAL_PTR(BP_VAR_R) TSRMLS_CC); FREE_OP1(); FREE_OP2(); CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); }
函數(shù)后兩個參數(shù)分別代表 op1 和 op2 可接受的操作數(shù)類型。
處理工具會根據(jù)這個函數(shù)的定義,對 op1 和 op2 進行類型組合,生成16個處理特定類型的 handler函數(shù)。這些 handler 函數(shù)命名如下:
static int ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* handler code */ } static int ZEND_FASTCALL ZEND_ADD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* handler code */ } static int ZEND_FASTCALL ZEND_ADD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* handler code */ } static int ZEND_FASTCALL ZEND_ADD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* handler code */ } static int ZEND_FASTCALL ZEND_ADD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* handler code */ } static int ZEND_FASTCALL ZEND_ADD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { /* handler code */ } ......
規(guī)律為:static int ZEND_FASTCALL OPCode_SPEC_{OP1-TYPE}_{OP2-TYPE}_HANDLER
所以最終執(zhí)行哪個 handler 是根據(jù)需要兩個操作數(shù)的類型決定的。
所以我們可以替換OPCode的handler,剛好源碼中有對應的接口zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)可供使用。
除了 OPCode 外,PHP 還有很多內(nèi)置函數(shù),比如 sprintf、 system、usort 等等,這些函數(shù)是沒有OPcode 的,但是這些函數(shù)都被保存在了全局函數(shù)表里,可以通過 CG(function_table) 獲取,這些函數(shù)也有對應的handler函數(shù)指針,所以我們可以直接備份原先的 handler 后使用 function->internal_function.handler = new_handler 替換即可。
到此這篇關于PHP 中的 RASP 實現(xiàn)流程分析的文章就介紹到這了,更多相關PHP 的 RASP 實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
解決php 處理 form 表單提交多個 name 屬性值相同的 input 標簽問題
這篇文章主要介紹了php 處理 form 表單提交多個 name 屬性值相同的 input 標簽問題的解決方法,需要的朋友參考下吧2017-05-05PHP實現(xiàn)的交通銀行網(wǎng)銀在線支付接口ECSHOP插件和使用例子
這篇文章主要介紹了PHP實現(xiàn)的交通銀行網(wǎng)銀在線支付接口ECSHOP插件和使用例子,需要的朋友可以參考下2014-05-05讓CodeIgniter的ellipsize()支持中文截斷的方法
CodeIgniter的Text Helper有一個ellipsize()方法,用來過濾HTML標簽并且截斷文字十分好用。但是它對中文支持的特別不好,在中文中使用就有亂碼出現(xiàn)。這篇文章主要介紹了讓CodeIgniter的ellipsize()支持中文截斷的方法,需要的朋友可以參考下2014-06-06Yii2針對游客、用戶防范規(guī)則和限制的解決方法分析
這篇文章主要介紹了Yii2針對游客、用戶防范規(guī)則和限制的解決方法,簡單分析了Yii2對于游客、用戶防范規(guī)則和限制的原理與相應的設置方法,需要的朋友可以參考下2016-10-10PHP網(wǎng)頁游戲學習之Xnova(ogame)源碼解讀(一)
這篇文章主要介紹了PHP網(wǎng)頁游戲Xnova(ogame)源碼解讀,需要的朋友可以參考下2014-06-06