8.6 不严谨的正则表达式

很多程序在判断文件上传扩展名、URL解析、入库参数等值的时候,都会使用正则表达式,正则表达式确实是一个非常方便和灵活的东西,能够帮助我们少写很多逻辑处理的代码,但是正则表达式也跟程序语言一样,规则写得不严谨,就会导致安全问题产生,至今已经有很多程序在这块栽了跟头,常见的几种问题如下。

1.没有使用^和$限定匹配开始位置

举例来说明,通过HTTP_CLIENT_IP来获取用户IP,其中这个值是可以被用户修改的,所以一般都会在服务端再过滤一下,看看是否被修改过,而过滤不严格的正则表达式很多都写成“\d+\.\d+\.\d+\.\d+”的形式,用代码来看看它的问题的在哪:


< php

$ip=$_SERVER['HTTP_CLIENT_IP']


if
preg_match '/\d+\.\d+\.\d+\.\d+/' $ip ))

{

    echo $ip


}

当请求头里面添加“client-ip:127.0.0.1aa”时输出127.0.0.1aa,同样通过检测,严谨一点的正则应该写成“^\d+\.\d+\.\d+\.\d+$”。

2.特殊字符未转义

在正则表达式里,所有能被正则表达式引擎解析的字符都算是特殊字符,而在匹配这些字符的原字符时需要使用反斜杠(\)来进行转义,如果不进行转义,像样英文句号(.)则可用来表示任何字符,存在安全隐患。下面介绍一个例子,代码如下:


< php

$filename=urldecode
'xxx.php%00jpg' );

if
preg_match '/. jpg|gif|png|bmp $/i' $filename ))

{

    file_put_contents
$filename 'aa' );

}

else{

    echo '
不允许的文件扩展名 '

}
>

从这段代码的意思可以看出,程序员原本是想检查文件的扩展名,如果不是图片文件则不允许上传,但是在检查扩展名的时候,正则表达式里面扩展名前面的点(.)没有进行转义,导致变成了全匹配符。如果这时候提交的文件名是'xxx.php%00jpg',则会绕过检查并写入一个PHP脚本文件。