原理
需要知識:正則NFA回溯原理,php的pcre.backtrack_limit設置。
正則NFA回溯原理
正則表達式是一個可以被"有限狀態自動機"接受的語言類。
"有限狀態自動機",擁有有限數量的狀態,每個狀態可以遷移到零個或多個狀態,輸入字串決定執行哪個狀態的遷移。
常見的正則引擎被分為DFA(確定性有限狀態自動機)與NFA(非確定性有限狀態自動機)他們匹配輸入的過程是:
DFA:從起始狀態開始,一個字符一個字符讀取輸入串,根據正則一步步確定至下一個轉移狀態,直到匹配不上或走完整個輸入。
NFA:從起始狀態開始,一個字符一個字符讀取輸入串,並與正則表達式進行匹配,如果匹配不上,則進行其他狀態。
狀態:輸入串被匹配的形式。
從上面過程可知,由於NFA存在回溯,所以性能會劣於DFA,但他支持更多功能,大多數語言都是以NFA作為正則引擎。
Demo
NFA的匹配模式:
正則:<\?.*[(`;?>].* 輸入串:<?php phpinfo();//aaaaa
匹配位置 | 模式 | 回溯 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 0 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 0 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 0 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 1 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 0 |
<?php phpinfo();//aaaaa | <\?.*[(`;?>].* | 0 |
通過表格可知,一共進行了八次回溯
什么是pcre.backtrack_limit()設置
對正則NFD回溯次數進行限制,能夠預防pcre ddos,默認值為1,000,000,如果超過限制,preg_match()
將會返回false,而如果preg_match匹配成功返回為1,匹配不成功返回為0。
安全問題出現原因
php的正則引擎是NFA,當preg_match()函數內正則的回溯次數超過pcre.backtrack_limit時,將會返回false。
漏洞出現的語法:
<?php
function is_php($data){
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
if(!is_php($input)) {
//code
}
?>
修復方案
if( is_php($input) === 0 )
// preg_match匹配成功返回int(1),失敗返回int(0) 而不是false