APP下载

PHP网站设计中SQL注入的安全防御

2014-09-10韩林利

淮阴工学院学报 2014年5期
关键词:表单字符攻击者

韩林利,魏 宁

(1.盱眙县生产力促进中心,江苏 盱眙 211700;2.淮安市科技局,江苏 淮安 223001)

0 引言

PHP全称为Hypertext Preprocessor,可以比CGI或者Perl更快速地执行动态网页,用PHP做出的动态页面与其他的编程语言相比,PHP是将程序嵌入到HTML文档中去执行,执行效率比完全生成HTML标记的CGI要高许多;PHP还可以执行编译后的代码,可以实现加密和优化代码运行的功能,使代码运行速度更快[1-2]。由于PHP程序编写简单,实用性强,消耗系统资源少,运行快,还具有较好的跨平台性,而且是免费的,因此PHP被广泛应用于网站的开发,特别适用于中小型网站的快速开发。虽然PHP的安全性较好,但还是存在SQL注入攻击等安全漏洞[3]。

1 PHP中SQL注入的产生

服务器和PHP的运行环境配置好后,并不意味着网络应用就安全了,程序员的安全意识也起着决定性的作用。如果在网络应用的开发阶段不注重网络应用的安全性,将为后期的网络安全维护带来巨大负担,例如在开发阶段对数据库的选择操作使用”SELECT * FROM Tablename”与”SELECT colum1,colum2 FROM Tablename”相比后者在遭受SQL SElECT攻击时泄露的信息要少的多。SQL注入的产生的主要原因是在网站开发初期程序员在编写代码的时候没有对用户输入数据的合法性进行判断,不仅包含用户输入数据在逻辑意义上的合法性,还包含用户输入数据是否含有数据库查询代码[4-6]。SQL注入的原理是网络应用系统在处理用户提交的表单信息时没有检查其合法性,用户在表单中填入SQL可执行的查询语句欺骗服务器执行恶意的SQL命令,网络应用程序在将表单信息发送到数据库存储时,数据库识别表中的SQL语句为可执行语句而执行并返回攻击者预期结果。这就是所谓的SQL Injection,即SQL注入[7-10]。

2 PHP中SQL注入的形式

SQL注入攻击的主要方式是构造巧妙的SQL语句,和网页提交的内容结合起来进行注入攻击。比较常用的方法有使用注释符号和恒等式、使用union语句进行联合查询、使用insert或update语句插入或修改数据等。

(1)经典的'or 1=1' 注入

'or 1=1'注入是非常经典的注入语句,一般用在登录系统时绕过密码验证,以任意用户名登入。其原理是在程序员编写验证程序的时候不需验证用户的输入是否含有非预期的字符串,直接传递给mysql_query()函数执行,'or 1=1'使得无论密码是否匹配,都能保证验证语句为真,达到绕过密码验证的目的。

正常语句:

SELECT * FROM user WHERE username = '$username' AND pwd = '$password'

注入语句:

SELECT * FROM user WHERE username = 'tom' AND pwd = ' ' or '1=1'

其中user是表名,包含有id、username、pwd和level等字段,分别表示了用户ID、用户名、密码和权限等级。这条注入语句利用了'1=1'这个恒等式作为逻辑判断,使得即使后面的pwd判断为假,该语句依然能够得到正确的执行,攻击者不需使用密码也能成功登录。

例如,访问http://admin.ev123.com/login.php,在用户名一栏填入admin' or ' 1'=' 1,密码为任意值,填入正确的验证码便可登录成功。测试网站成功登陆的界面分别如图1和图2所示。

图1 登陆界面

(2)利用UNION语句的注入

UNION语句注入式利用其语句特性,是程序默认的语句,在执行后将结果集与攻击者给定的SQL语句执行结果集相合并到一起返回给攻击者,达到注入的目的。

图2 登录成功界面

该攻击方法的一般步骤是首先选取攻击页面,从整体网站的结构角度进行猜测,或通过多个功能页面对比出URL,或在表单中提交字段的意义,随后在提交关键字中插入构造好的SQL注入语句。一般情况下注入的步骤是:首先通过注入语句获取服务器中的数据库名;然后通过注入语句获取数据库中表名,在通过注入语句获取数据表中字段名;最后获取数据库字段中的内容。由于注入语句执行的结果需要依靠系统既定的页面显示,所以注入语句获取的信息内容需要结合页面显示的框架灵活调整。例如,正常访问网址http://127.0.0.1:8081/search.php?year=2014,该页面可以显示出数据库中的出生年是2014年的所有用户信息,其中year=2014的部分通过开发过程中常见的传值方式可以猜测出,在数据库的后台应该含有类似SELECT * FROM 表名 WHERE year=2014的SQL查询语句,不同的是在选择的列名和列的维数上可能存在限制,比如实际的SQL语句可能是SELECT column1,column2,column3 FROM 表名 WHERE year=2014,这样就会导致在后期进行注入的时候需要考虑SQL语句中选择语句的维数限制,使用union语句进行注入时,可以通过PHP页面的数据维数辅助确定SELECT语句的维数。从页面上可以看出SQL语句含有三列数据。使用union语句注入首先要查看MySQL中含有哪些数据库,可以在浏览器中构造URL请求:http://127.0.0.1:8081/search.php?year=2014%20and%201=2%20union%20select%20 SCHEMA_NAME,SCHEMA_NAME,SCHEMA_NAME%20from%20information_schema.SCHEMATA%20limit%200,6,可以获取服务器上安装的数据库名,如图3所示,随后构造请求字符串:http://127.0.0.1:8081/search.php?year=2014%20and%201=2%20union%20select%20TABLE_NAME,TABLE_NAME,TABLE_NAME%20from%20information_schema.TABLES%20where%20TABLE_SCHEMA=%27sample%27%20limit%200,3,可以获取服务器上的数据库表名,如图4所示,随后构造请求字符串:http://127.0.0.1:8081/search.php?year=2014%20and%201=2%20Union%20select% 20COLUMN_NAME,COLUMN_NAME,COLUMN_NAME%20from%20information_schema.COLUMNS%20where%20TABLE_NAME=%27login%27%20limit%200,3,可以获取数据库表中所含有的字段名,如图5所示,下一步可以构造请求字符串:http://127.0.0.1:8081/search.php?year=2014%20UNION% 20SELECT%201,pass,3%20from%20login%20WHERE%20id=1,如图6所示。

图3 获取数据库名

图4 获取数据库表名

图5 获取表字段名

通过以上几个步骤就可以获得用户的密码等相关信息。

(3) 使用INSERT语句

图7 用户登录界面

图8 使用INSERT语句进行注入

INSERT语句注入主要结合SQL语句中的注释符使程序预定插入的值变成SQL注释部分,从而达到注入的目的。使用insert语句注入主要是在注册页面进行注入,图7是一个普通的用户注册页面,用户在输入用户名密码后,系统会自动地给用户赋予权限值3,在数据库端的SQL语句是INSERT INTO reg(uname,pass,power) VALUES('user1','userpass',3),可以利用MYSQL的注释字符对其进行注入,测试用例在pass字段上进行注入,如图8所示,原理是通过人为构造“’”,使得原本合法的SQL语句权限部分失效;如果要使得注入的权限值有效,只需在用户密码框字段输入user1pass',1)#,用户名字段输入user1即可在系统创建一个用户名为user1、密码为user1pass、权限是1的用户,如图9所示。

3 SQL注入的防范

(1)对输入的数据进行过滤(过滤输入)

1)对于动态构造SQL查询的场合,可以使用替换字符和删除特殊字符的方法。替换字符是把所有单独出现的单引号改成两个单引号,以防止攻击者修改SQL命令的含义。删除特殊字符,是防止攻击者构造出类似“select * from Userswhere admin = 'AAA' —— and password =”之类的查询,因为这类查询的后半部分已经被注释掉,不再有效,攻击者只要知道一个合法的用户登录名称,根本不需要知道用户的密码就可以顺利获得访问权限。

2)检查用户输入的合法性,防止非法数据输入。数据检查应当在客户端和服务器端执行。执行服务器端验证,是为了弥补客户端验证机制的不足。因为在客户端,攻击者很有可能获得网页的源代码,修改验证合法性的脚本(或者直接删除脚本),然后将非法内容通过修改后的表单提交给服务器。因此,为了确认是否执行了验证操作,就需在服务器端也执行验证,可以使用许多内建的验证对象,例如RegularExpressionValidator,也可采用插入服务器端的方法调用,同时系统可以检测系统用户的输入数据内容,发现含有输入语句时,可以将页面转发到系统出错页面以规避攻击者不断地向系统注入式攻击导致系统处理性能下降。图10是测试用的普通用户注册页面,图11是进行INSERT语句注入错误处理页面,图12是系统后台对用户输入进行检测的状态监控的页面,可以向系统管理员显示攻击者输入的注入语句,以方便管理员及时发现系统漏洞并加以修补。

图10 注册页面

3)限制表单或查询字符串输入的长度范围。如果用户的登录名字范围在6~10个字符,那么不要认可表单中输入的6个以下和10个以上的字符,从而增加攻击者在SQL命令中插入恶意代码的难度。

图12 系统检测页面

4)加密用户登录名称、密码等数据。加密输入的数据后,再将它与数据库中保存的数据进行比较,这就相当于对用户输入的数据进行了“消毒”处理,用户输入的数据不再对数据库有任何特殊的意义,从而也就防止了攻击者注入SQL命令。

5)检查提取数据的查询所返回的记录数量。假如程序只要求返回一定数目的记录,但实际返回的记录却超出了程序要求返回的数目,那就把该查询操作当作非法处理。

过滤输入内容可以按多种方式进行,示例如下。

*过滤sql与php文件操作的关键字

private function filter_keyword( $string ){

$keyword='select|insert|update|delete|’|‘〔|〔|。。‘|。‘|union|into|load_file|outfile';

$arr = explode('|', $keyword);

$result = str_ireplace($arr, '', $string);

return $result;

}

*检查输入的数字是否合法,合法返回对应id,否则返回false

protected function check_id( $id ){

$result = false;

if($id!== '' && !is_null($id)){

$var= $this->filter_keyword( $id ); // 过滤sql与php文件操作的关键字

if ( $var !== '' && !is_null( $var ) &&is_numeric( $var ) ){

$result = intval( $var );

}

}

return $result;

}

* 检查输入的字符是否合法,合法返回对应id,否则返回false

protected function check_str($string){

$result = false;

$var = $this->filter_keyword( $string ); // 过滤sql与php文件操作的关键字

if(!empty($var)){

if(!get_magic_quotes_gpc()){ // 判断magic_quotes_gpc是否为打开

$var = addslashes($string); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤

}

$var = str_replace("_", "—", $var); // 把 '_'过滤掉

$var = str_replace("%", "\%", $var); // 把 '%'过滤掉

$var = nl2br($var); // 回车转换

$var = htmlspecialchars( $var ); // html标记转换

$result = $var;

}

return $result;

}

(2)对发送到数据库的数据进行转义(转义输出)

尽量使用为自定义数据库设计的转义函数。如果没有,使用函数addslashes()是比较好的方法,对字符串型参数使用mysql_real_escape_string函数、对数字型参数使用intval,floatval函数强制过滤则更好。当所有用于建立一个SQL语句的数据被正确过滤和转义时,实际上也就避免了SQL注入的风险。

如对mysql用户,可以使用mysqlreal_escape_string函数实现。mysql_real_escape_string会调用MySQL的库函数mysql_real_escape_string,对(x00), ( ), ( ), (), (‘), (x1a)进行转义,即在前面添加反斜杠(),预防SQL注入。但该函数并不转义 % 和 _。最好不要对整条sql语句使用该函数,而是只转义转入sql语句的字符串参数,否则会发生意想不到的结果。

addslashes对SQL语句中的特殊字符进行转义操作,包括(‘), (“), (), (NUL)四个字符,此函数在DBMS没有自己的转义函数时候使用,但是如果DBMS有自己的转义函数,那么推荐使用原装函数,比如MySQL有mysql_real_escape_string函数用来转义SQL。

htmlentities把HTML中可以转义的内容转义成HTML Entity。html_entity_decode为htmlentities的decode函数。

htmlspecialchars把HTML中的几个特殊字符转义成HTML Entity(格式:&xxxx;)形式,包括(&),(‘),(“),(<),(>)五个字符。htmlspecialchars可以用来过滤$GET,$POST,$COOKIE数据,预防XSS。注意htmlspecialchars函数只是把认为有安全隐患的HTML字符进行转义,如果想要把HTML所有可以转义的字符都进行转义的话请使用htmlentities。

(3)打开magic_quotes_gpc或 magic_quotes_runtime 选项

打开magic_quotes_gpc选项,并关闭错误提示display_errors=off,不给攻击者提供敏感信息,这样所有的客户端GET和POST的数据都会自动进行addslashes处理,使得对字符串值的SQL注入不可行。

打开magic_quotes_runtime 选项时,从文件中读取的数据或执行exec()的结果或是从SQL查询中得到的,数据都会自动进行转义。

(4)使用PDO连接数据库

防止SQL注入最好的方法就是不要自己设置SQL命令和参数,而是用PDO的prepare和bind,原理就在于要把SQL查询命令和传递的参数分开。使用prepare的时候,DB server会把SQL语句解析成SQL命令。使用bind的时候,只是动态传递DB Server解析好的SQL命令。

另外使用rewrite技术隐藏真实脚本及参数的信息,通过rewrite能过滤可疑的参数,而不必使用具有FILE权限的账号(比如root)来连接MySQL,也能屏蔽load_file等危险函数。

4 结束语

针对PHP的网站存在多种攻击方式,如命令注入(Command Injection)、eval注入(Eval Injection)、客户端脚本攻击(Script Insertion)、跨网站脚本攻击(Cross Site Scripting, XSS)、SQL注入攻击(SQL injection)、跨网站请求伪造攻击(Cross Site Request Forgeries, CSRF)、Session 会话劫持(Session Hijacking)、Session 固定攻击(Session Fixation)、HTTP响应拆分攻击(HTTP Response Splitting)、文件上传漏洞(File Upload Attack)、目录穿越漏洞(Directory Traversal)、远程文件包含攻击(Remote Inclusion)、动态函数注入攻击(Dynamic Variable Evaluation)、URL攻击(URL attack)、表单提交欺骗攻击(Spoofed Form Submissions)、HTTP请求欺骗攻击(Spoofed HTTP Requests)等,其中SQL注入攻击较多。SQL注入是从正常的WWW端口访问,而且表面上跟一般的Web页面没什么区别,所以目前市面的防火墙都不会对SQL注入发出警报,对其必须加强技术防范。SQL注入攻击主要针对的是应用开发过程中编程的不严密,因而防范SQL注入攻击的主要方法就是完善编程,另外对服务器端进行合理配置,封住SQL注入漏洞,如把IIS设置成屏蔽错误提示,也能有效防范SQL注入攻击。

参考文献:

[1] 数位文化. php4交互网页数据库实战手册[M].北京:清华大学出版社,2004.

[2] 渠芳,曹志梅.ASP,PHP和JSP技术的比较研究[J].现代情报,2002 (7):50-52.

[3] 龙浩.PHP语言进阶和高级应用[M].北京:清华大学出版社,2002.

[4] 焦桐顺. phpmysql数据库开发指南[M].北京:电子工业出版社, 2001.

[5] Hugh E.Williams. PHP & MYSQL Web数据库应用开发指南[M].谢君英,欧阳宇,译.南京:东南大学出版社,2003.

[6] 陈浩.PHP 程序设计[M].北京:电子工业出版社,2005.

[7] 邵煜.PHP和MYSQL WEB开发[M].北京:机械工业出版社,2005.

[8] David Lane.PHP & MYSQL WEB数据库应用开发指南[M].南京:东南大学出版社,2006.

[9] Mihai Bucica.AJAX与PHP WEB开发[M].北京:人民邮电出版社,2007.

[10] PETER MOULDING.PHP技术内幕[M].北京:中国水利水电出版社,2003.

猜你喜欢

表单字符攻击者
机动能力受限的目标-攻击-防御定性微分对策
电子表单系统应用分析
字符代表几
一种USB接口字符液晶控制器设计
HBM电子称与西门子S7-200系列PLC自由口通讯
消失的殖民村庄和神秘字符
正面迎接批判
浅谈网页制作中表单的教学
有限次重复博弈下的网络攻击行为研究
动态表单技术在教学管理中的应用*