php web开发安全之sql注入和防范:(一)简单的select语句注入和防范
sql注入主要是指通过在get、post请求参数中构造sql语句,以修改程序运行时所执行的sql语句,从而实现获取、修改信息甚至是删除数据的目的,sql被注入的原因主要是代码编写的有问题(有漏洞),只要平时注意在编写与sql相关的代码时养成良好的习惯,对可能被注入的sql语句加以防范,那么在大部分情况下是可以防范sql注入的。下面看下哪些不好的编码习惯容易引起select语句被注入,并分析下防范措施。
注意:这里没有完整的php代码,可以大致假设一个场景:用户可以通过类似下面的url地址http://localhost/user.php?username=yang或http://localhost/user.php?uid=yang,通过get方法来请求数据库中的信息,数据库中有user、article表。
1,sql语句中的替换变量不加引号
看下这条语句 $sql = "select uid, username from user where uid = $uid ";
替换变量不加引号,如果用户输入这样的$uid:$uid = '1 and 1=2 union select * from article where aid = 1';
那么可以构造出这样的sql
select uid, username from user where uid = 1 and 1=2 union select * from article where aid = 1
可以看到结合union,就可以对其他表中的数据进行查询。
所以,sql语句中的变量应该要加上引号 $sql = "select uid, username from user where uid = '$uid'";
这样即便被sql注入,被构造的sql语句也只会变成这样:
select uid, username from user where uid = '1 and 1=2 union select * from article where aid = 1';
这样构造出的uid就只能是sql语句中查询参数的值,也就起不到注入作用了。
2,未对用户的输入进行过滤和转义
(1)过滤,对数据进行过滤,将其转换为自己需要的格式,或者判断数据格式是否合法。判断数据格式是否合法这个要按照自己定义的规则来进行,比如email地址格式、用户名长度和组合、密码长度和组合等,这里先不讨论数据格式合法性的问题。下面先简单看下格式转换问题:
对于按id查找的sql,因为id一般为整数,所以可以先将用户输入的数据类型转换为int,这样即使用户尝试构造$uid为:
$uid = (int)'1 and 1=2 union select * from article where aid = 1' ,
它也会被转换为数字,这在一定程度上能够避免被注入。
(2)对于按如username字符串类型查找的sql,面临的主要注入风险是通过在参数中加上单引号、sql注释符、sql语句结束符等符号来构造sql,所以只要注意将这些字符进行转义即可,也就是对用户输入的数据进行转义,这里涉及到两个函数:addslashes()和 addcslashes()。addslashes()可以对单引号'、双引号"、反斜线\和NUL(NULL字符)进行转义。addcslashes()可以自定义需要转义的字符,下面来看下利用addcslashes()对用户的输入进行转义。
比如下面这条sql语句:
$sql = "select uid, username from user where username = '{$username}' ";
在不进行转义的时候,用户可以构造$username如下: yang';SHOW TABLES-- inject
最后构造出如下的sql:
select uid, username from user where username = 'yang';SHOW TABLES-- inject';
现在我们用addcslashes()函数对$username进行转义,
$username = isset($_GET['username']) ? addcslashes($_GET['username'], "'\"%_\\;-") : '';
注意上面的语句会对下面的字符进行转义 ,可以根据实际需要转义相应的字符。
' 单引号 " 双引号 % 百分号 _ 下划线 \ 反斜线 ; 分号 - 小破折号
这时如果用户构造的 yang';SHOW TABLES-- inject 就会变成这个样子: yang\'\;SHOW TABLES\-\- inject ,构造的sql会变成这样:
select uid, username from user where username = 'yang\'\;SHOW TABLES\-\- inject';
可以说是惨不忍睹了,sql注入也就失效了。
3,小结
上面只是简单的分析了容易被sql注入的两个不好的编程习惯和相应的防范,其实sql注入的方式、方法还有很多,所谓魔高一尺、道高一丈,需要学习的地方还有很多。
参考: