SQL注入攻击是黑客对数据库进行攻击的常用手段之一。随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但是由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。
我们来看一个简单的sql注入攻击:
String sql="select* from tb_name where name='"+varname+"' and passwd = '"+varpasswd+"'";
如果我们把[a or 1=1]作为varpasswd传入进来.用户名随意,看看会成为什么?
Select * from tb_namewhere name= '随意' and passwd=a or 1=1;
因为1=1肯定成立,所以可以任何通过验证.
更有甚者:
把[a;drop table tb_name;]作为varpasswd传入进来,则:
select* from tb_name where name ='随意' and passwd=a;drop table tb_name;有些数据库是不会让你成功的,但也有很多数据库就可以使这些语句得到执行。
防止SQL注入攻击的方法主要是对用户输入数据的合法性进行判断,过滤危险字符。Java和php都提供了预编译(prepare)的方式来防止sql注入攻击。下面介绍php中pdo如何防止sql注入。
$num = 10;
$os = 'android';
// 实例化数据抽象层对象
$db = new PDO("mysql:host=localhost;dbname=test;","root","");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // 禁用prepared statements的仿真效果
// 对 SQL 语句执行 prepare,得到 PDOStatement 对象
$stmt = $db->prepare('SELECT logtime FROM
t_log
WHERE os = ?
limit ?');
// 绑定参数
$stmt->bindParam(1, $os ,PDO::PARAM_STR);
$stmt->bindParam(2, $num, PDO::PARAM_INT);
// 查询
$stmt->execute();
// 获取数据
$res = $stmt->fetchAll();
print_r($res);
sql语句和参数分两次发送到mysql服务器,Prepare语句保证了sql语句的预编译,因此参数还未传到mysql服务器前,已经完成了sql语句的编译,参数传来后,只是替换占位符而已。所以即使参数中带sql注入,都不会被编译,也就杜绝了sql注入攻击。
但是我们需要注意的是以下几种情况,prepare并不能帮助你防范SQL注入。
1. 不能让占位符 ? 代替一组值,这样只会获取到这组数据的第一个值,如:
select * from table where userid in ( ? );
如果要用in來查找,可以改用find_in_set()实现
2. 不能让占位符代替数据表名或列名,如:
select * from table order by ?;
3. 不能让占位符 ? 代替任何其他SQL语法,如:
select extract( ? from addtime) as mytime from table;