前言:有的时候会想写一篇自己对PHP 代码的安全编写的看法,如果你或许正想了解一些关于
PHP 代码编写环境中可以遇见的安全隐患,如果你觉得你可能可以靠这篇文档回忆起以前编写PHP
环境中忽视的问题,那么你停在这一页,这篇文档就是期望试图来说清,我们究竟有一些什么样的
忽视会被人利用呢?
变量
变量是 PHP 本身运行的基础,说到变量,我们则需要再注意一下 PHP.ini 里对我们变量会造成
一些其他影响的设置。
register_globals
这个设置在 PHP 4.2.0 开始默认为 Off,它的作用是把用户提交的 GET、POST、COOKIE、
SESSION 、 FILES 等 变 量 转 成 全 局 变 量 , 例 如 当 你 在 浏 览 器 提 交 类 似
http://localhost/register.php?text=test
那么,除了本身的 GET 的变量外,会增加一个 $text=’test’; 这样的变量,但是原来变量
已经被定义的话,则不会覆盖。
magic_quotes_gpc
这个设置默认为 ON ,它中文的名字叫魔法引用,它的作用是把用户提交的 GET 、POST 、
COOKIE 等变量用类似addslashes 的方式在 ’、”、\ 这三个和 NULL 字符前加上 \ 字符进行转
义。
当然,在 PHP.ini 里不免有其他的设置可以影响到我们的变量。由于很多原因,我们在这里暂
列出这两个关键性的设置。register_globals 和 magic_quotes_gpc 在 PHP 4.3.9 以后的默认设置都是
很安全的,但是由于编写程序的种种方便,编写者总是会以其他函数的方式来实现 register_globals
这样的功能。而下面,我们就要讲到的是函数,这对我们的变量的影响也是很大的。
函数
extract
这个函数在 PHP 3.0.7 到现在都存在,一般的时候程序员会用它来在 register_globals 为 OFF
的时候进行类似的操作,而这个函数在不同的参数的时候有着不同的能力,而一般最主要要注意的
是下面两个。
EXTR_OVERWRITE 如果有冲突,覆盖已有的变量。
EXTR_SKIP 如果有冲突,不覆盖已有的变量。
第一个参数在手册上写得很清楚了,如果变量已存在,则会覆盖原来的变量,而下面的一个则
是不会覆盖原有变量,但是如果提交的变量本不存在,则会产生一个全局变量,在这里我们需要注
意的是,当在这里不指明这函数的第二个变量的时候,默认使用 EXTR_OVERWRITE
大家可以写下面这样一小段代码来进行测试。
代码片段
<?PHP
$str = 1;
@extract($_GET,EXTR_OVERWRITE);
echo $str;
?
把它存为 test.PHP,然后在浏览器里提交http://localhost/test.php?str=atest,则会打印出 atest 这
样的字串,自然,为了显示出这样的效果,我把 extract 放到了 str 赋值的后面,而实际上,只要
你像这样使用这个函数,它是无论如何都会影响到 GLOBALS 里的数据,例如 FILES、SESSION、
GET、POST、COOKIE 等 PHP 本身创建的变量值。
urldecode
这个函数用来返回 URL 编码后的字符串,这个在 PHP 编写环境中是较为常见的,但是滥用它
可能会影响magic_quotes_gpc 本身的操作,大家可以写入如下的代码进行测试。
代码片段
<?PHP
echo urldecode($_GET['url']);
?
我们在开启 magic_quotes_gpc 的情况以下面的 Url 去浏览这个页面:
http://localhost/urldecode.php?url=%2527
你会发现,页面打印的是一个单引号,在这个时候, magic_quotes_gpc 本身的作用已经被彻
底的破坏了,因为,我们提交的字符到服务器的时候实际上是 %27,再被 urldecode 的时候则会还
原成单引号,在这里,我们可以提交任意 magic_quotes_gpc 本身处理过的单引号,双引号,反斜
杠以及 NULL 字符。
substr
这个函数用来返回处理变量的一部分,这个函数在PHP 编程环境中应用很广,可是,在不仔细
处理的时候,它也可能会遗留下本来不被期望的字符。
例如下面这样的代码:
代码片段
<?PHP
echo substr($_GET['text'], 1);
?
从我们提交的 text 里第二位开始取值,那么,如果我们提交http://localhost/text.php?text=abcd的
时候,则会被截取成 bcd,而当我们提交http://localhost/text.php?text=’bcd的时候,则会显示 ’bcd,
反斜杠被 substr 给去掉了。
这样的情况是因为 substr 在我们提交 ’bcd 的时候实际操作的是 \’bcd,所以会把 \ 给截取,
然后留下 ’bcd 这样的字符串。
由于很多原因,关于函数方面可能的疏忽没有办法在这里一一列出,而后要讲的是代码安全编
写的建议,代码的安全是一个整体,即使我把所有已知可能疏忽的函数一一列出,也无法解决一个
代码的安全,下面要说到的是较为安全的编码规范。
编码规范
不管我们鉴于还是不鉴于 extract 或是 register_globals 这样的情况,被建议的编写方式
是,所有使用到的全局变量必须被初始化。
数字,数组,字符串的初始化应当不同,否则可能会在下面引用的时候导致不必要的错误,建
议的初始化方式类似下面这样。
数字的初始化:$str = 0;
字符串的初始化:$str = ‘’;
数组的初始化:$str = array(‘’);
为什么不会把所以变量全初始为空呢?因为这样的话,类似foreach 操作的时候,则会得到一个
错误,而按我们上面这样的初始化的话,则不会发生类似这样的问题。
而这些变量的初始化建议在使用这个变量前几行进行初始化,且最好不要把初始化放在 if 语句
之中进行。如果不这样做会有什么后果呢,看一下本期后面的一篇文章《PHP 程序安全性的八百种
死法 之 未初始化的变量》你就知道啦。?