同事维护的站点遇到一个SQL注入漏洞,最后发现是由于对in_array()的理解错误(一直以为是绝对匹配才会返回true),同时拼接SQL语句时也没有使用Prepared Statement导致。代码中使用in_array($var, $white_set)判断从Query String获得的变量是否符合要求,参见下面示例代码($var为一整型变量,取用时没有使用intval($var)或者(int)$var强制转换为整型)。

$white_set = array(11, 13, 16);
$var = $_GET['var'];
if (in_array($var, $white_set)) {
    $query =   column =  . $var .   ;
    
}

访问 http://www.example.com/path/to?var=16′ and ‘x’=' 时,$var=16′ and ‘x’=',使用in_array($var, $white_set) 判断会得到 true,因为 in_array 的第三个参数默认为 false,此时在依次比较 $var$white_set 中的元素会进行类型转换,相当于使用 == 进行比较;如果第三个参数为 true,则相当于使用 === 进行比较,两个变量只有完全一致才会返回 true

总结:in_array() 第三个参数决定变量和数组中元素如何进行比较。 值为 false 时(默认),相当于 ==;值为true时,相当于 ===