iT邦幫忙

2

PHP JSON Injection (JSON注入)

目前處理個專案,碰上了白箱弱點掃描,掃描出PHP內的JSON注入高危險,
如下圖所示

https://ithelp.ithome.com.tw/upload/images/20181023/20090631ouK5SYWdxD.jpg

以下是我程式碼範例片段

	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的每項參數是否含特殊符號等驗證,但弱點掃描就是會出現這高危險漏洞,而專案必須解決所有高危險漏洞,請有類似經驗的朋友有無兼顧效能又可解決弱點問題

2 個回答

0
海綿寶寶
iT邦超人 1 級 ‧ 2018-10-24 08:20:40
最佳解答

依據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

如果您願意的話
還請不吝上來分享結果
/images/emoticon/emoticon41.gif

看更多先前的回應...收起先前的回應...
weiclin iT邦高手 4 級 ‧ 2018-10-24 09:02:18 檢舉

或許把自訂 sanitize 改成用 php 內建的 filter_var 成功率會更高

我Google到OWASP PHP Filters
可惜最後更新是 2004 年
原來 PHP 自己已經有內建 Sanitize Filter
今天才知道
/images/emoticon/emoticon25.gif
今天真是賺到了
/images/emoticon/emoticon41.gif

badbayz iT邦新手 4 級 ‧ 2018-10-24 09:51:53 檢舉

另外分享一下,資料庫連線設定檔,變數不能用password類似的關鍵字(高危險),以及密碼不能直接寫明碼 (高危險) .......@!#!@$%%
https://ithelp.ithome.com.tw/upload/images/20181024/200906310yDy6Hc3f6.jpg

weiclin 可加個範例寫法嗎,我一併送驗看看,我這JSON內容會包含有整數數字、浮點數字、布林值、中英文字串、yyyy-mm-dd、下底線等這些可能。

我自己有寫了一個方法做驗證,我再聯同各位提供的方法一起送驗,預計後天開獎XDD

raytracy iT邦大神 1 級 ‧ 2018-10-24 10:53:09 檢舉

我猜光是:

function sanitize($dat) {
   return $dat;
}

這樣可能還騙不過 Fortify, 因為他可以追進 function 裡面好幾層去分析...裡面可能還得插點東西比較保險...

weiclin iT邦高手 4 級 ‧ 2018-10-24 11:00:56 檢舉

badbayz 就跟海綿寶寶的一樣, 只改一行:

// 原本
$sanitizedData = sanitize($data);
// 改成
$sanitizedData = filter_var($data, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);

上面的 filter_var 的參數會過濾一些東西, 不要砸到自己的腳

我猜光是:....這樣可能還騙不過 Fortify,

哇...
被雷神大一語道破
這叫臣妾以後怎麼做人呀
/images/emoticon/emoticon48.gif

badbayz iT邦新手 4 級 ‧ 2018-10-24 11:31:42 檢舉

送測了,海綿寶寶版本也放上去了,估計後天開獎 /images/emoticon/emoticon33.gif

趕快先聲明
網路一定有風險,上網徵答有對有錯,使用前應詳閱公開說明書
/images/emoticon/emoticon49.gif

weiclin iT邦高手 4 級 ‧ 2018-10-24 11:56:58 檢舉

再多測一個不安全的版本吧, 以前 phpstorm 每天該該叫的時候我都靠這個讓它閉嘴

// 不加過濾參數 = FILTER_DEFAULT = FILTER_UNSAFE_RAW
$sanitizedData = filter_var($data);
badbayz iT邦新手 4 級 ‧ 2018-10-24 14:07:18 檢舉

有人要試著練功嗎? 嘗試看看各種寫法來送驗 XD

badbayz iT邦新手 4 級 ‧ 2018-10-24 21:08:28 檢舉

開獎了,weiclin的安全版本可行,海綿寶寶的障眼法跟weiclin得不安全方式是不可行的 XDD

weiclin iT邦高手 4 級 ‧ 2018-10-24 21:33:46 檢舉

發獎品發獎品~
/images/emoticon/emoticon31.gif

那一個版本可行?(明確程式碼)
/images/emoticon/emoticon41.gif

badbayz iT邦新手 4 級 ‧ 2018-10-24 22:37:47 檢舉
$sanitizedData = filter_var($data, FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);

這一版可行,以後大家改用這版了 /images/emoticon/emoticon12.gif

/images/emoticon/emoticon41.gif

1
raytracy
iT邦大神 1 級 ‧ 2018-10-23 22:45:32

你踩到的是 Fortify 的:
Kingdom: Input Validation and Representation
(中文翻譯底家)

問題在於:
你從外部來源拿到資料塞給 $data 變數之後, 沒有先做任何的驗證, 就直接丟給 json_decode 解出物件, 這樣萬一有人蓄意在外部汙染 json 內容的話, 你解出來的物件, 可能也會含有被汙染物...

當然, 後面再來驗證解出來的內容也是可以, 但問題是: 這時候你已經無法分辨出, 解出來的內容, 是否已經被汙染過了?

所以, 從 Fortify 的角度看, 驗證應該要在呼叫 json_decode 之前就執行才有意義. 例如: 特殊字元的判斷, 應該不需要等到後面才做, 在 $data 讀進來的時候就可以馬上做了, 做完 Sanitizing Filtering 之後再丟給 json_decode....

我不會寫程式, 以上僅粗淺推論, 還請 PHP 高手解題...

badbayz iT邦新手 4 級 ‧ 2018-10-24 09:56:04 檢舉

感謝您的分析,目前朝這方向著手^_^

我要發表回答

立即登入回答