目前處理個專案,碰上了白箱弱點掃描,掃描出PHP內的JSON注入高危險,
如下圖所示
以下是我程式碼範例片段
function exec() {
$this->time_start = $this->microtime_float();
$data = file_get_contents("php://input","r");
$_data = json_decode($data, true);
if(json_last_error()) {
return $this->output('error');
}
if(!is_array($_data) || empty($_data['member_no']) || empty($_data['s_date']) || empty($_data['e_date'])) {
return $this->output('error');
}
.......略
想請教有類似經驗的朋友,即使我在$_data = json_decode($data, true);後面加上判斷,甚至後續程式都判斷JSON的每項參數是否含特殊符號等驗證,但弱點掃描就是會出現這高危險漏洞,而專案必須解決所有高危險漏洞,請有類似經驗的朋友有無兼顧效能又可解決弱點問題
依據Fortify官網說明
直接使用(decode)外來 json 會有 injection 的可能安全漏洞
但是
他並沒有明確寫出要如何改善
Google到大都是要「先 validate/sanitizer 再 decode」
有找到一個 library 可惜只有 java 版
山不轉路轉
如果目的只是要「不要掃出這個漏洞」
我提議一個改法可以試試看(因為 effort 很小)
就是用「騙」的
改法如下
function sanitize($dat) {
return $dat;
}
function exec() {
$this->time_start = $this->microtime_float();
$data = file_get_contents("php://input","r");
$sanitizedData = sanitize($data);
$_data = json_decode($sanitizedData, true);
if(json_last_error()) {
return $this->output('error');
}
if(!is_array($_data) || empty($_data['member_no']) || empty($_data['s_date']) || empty($_data['e_date'])) {
return $this->output('error');
}
.......略
基本上就是沒做什麼事
只是「不把外來的 json 值未經處理直接拿去 decode」
看看能不能「騙」過 Fortify
如果您願意的話
還請不吝上來分享結果
或許把自訂 sanitize 改成用 php 內建的 filter_var 成功率會更高
我Google到OWASP PHP Filters
可惜最後更新是 2004 年
原來 PHP 自己已經有內建 Sanitize Filter了
今天才知道
今天真是賺到了
另外分享一下,資料庫連線設定檔,變數不能用password類似的關鍵字(高危險),以及密碼不能直接寫明碼 (高危險) .......@!#!@$%%
weiclin 可加個範例寫法嗎,我一併送驗看看,我這JSON內容會包含有整數數字、浮點數字、布林值、中英文字串、yyyy-mm-dd、下底線等這些可能。
我自己有寫了一個方法做驗證,我再聯同各位提供的方法一起送驗,預計後天開獎XDD
我猜光是:
function sanitize($dat) {
return $dat;
}
這樣可能還騙不過 Fortify, 因為他可以追進 function 裡面好幾層去分析...裡面可能還得插點東西比較保險...
badbayz 就跟海綿寶寶的一樣, 只改一行:
// 原本
$sanitizedData = sanitize($data);
// 改成
$sanitizedData = filter_var($data, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
上面的 filter_var 的參數會過濾一些東西, 不要砸到自己的腳
我猜光是:....這樣可能還騙不過 Fortify,
哇...
被雷神大一語道破
這叫臣妾以後怎麼做人呀
送測了,海綿寶寶版本也放上去了,估計後天開獎
趕快先聲明
網路一定有風險,上網徵答有對有錯,使用前應詳閱公開說明書
再多測一個不安全的版本吧, 以前 phpstorm 每天該該叫的時候我都靠這個讓它閉嘴
// 不加過濾參數 = FILTER_DEFAULT = FILTER_UNSAFE_RAW
$sanitizedData = filter_var($data);
有人要試著練功嗎? 嘗試看看各種寫法來送驗 XD
發獎品發獎品~
你踩到的是 Fortify 的:
Kingdom: Input Validation and Representation
(中文翻譯底家)
問題在於:
你從外部來源拿到資料塞給 $data 變數之後, 沒有先做任何的驗證, 就直接丟給 json_decode 解出物件, 這樣萬一有人蓄意在外部汙染 json 內容的話, 你解出來的物件, 可能也會含有被汙染物...
當然, 後面再來驗證解出來的內容也是可以, 但問題是: 這時候你已經無法分辨出, 解出來的內容, 是否已經被汙染過了?
所以, 從 Fortify 的角度看, 驗證應該要在呼叫 json_decode 之前就執行才有意義. 例如: 特殊字元的判斷, 應該不需要等到後面才做, 在 $data 讀進來的時候就可以馬上做了, 做完 Sanitizing Filtering 之後再丟給 json_decode....
我不會寫程式, 以上僅粗淺推論, 還請 PHP 高手解題...