2017/06/28

sql防注入


sql注入就是用户在向服务器传输数据时,携带了恶意的sql语句,服务器这边在没有进行严格的处理直接把用户的数据代入mysql指令中,则将很容易出现被注入攻击的可能。举个例子:

$nick = $_POST['nick'];
$sql = "SELECT * FROM role WHERE nick={$nick}";
用户可以输入demo; DROP TABLE role;然后查询语句就变成了这样

"SELECT * FROM role WHERE nick=demo; DROP TABLE role;";

预防注入,做法是把需要提交到数据库执行的数据进行转义,保证数据进入到数据库是安全的,不同的扩展库有不同的转义方法:

mysql 扩展库使用 mysql_real_escape_string
mysqli 扩展库使用 real_escape_string
PDO 可使用 prepareexecute

注意php7已经全面废弃了 mysql_ 的接口,推荐使用 mysqli 或 PDO。

在 Codeigniter 框架中,配置database.php下的dbdriver参数,如果选用mysql扩展库,则后面的AR模型操作时,对每个数据都会调用 mysql_real_escape_string 进行转义;如果选用mysqli扩展库,则会调用 real_escape_string 进行转义。在不同的php框架中,我们通常都会推荐使用者使用AR模型进行操作数据,因为框架对会封装一层转义处理在里面,保证安全。


PDO例子

<?php

$dbms='mysql'; // 数据库类型
$host='127.0.0.1:3306'; // 数据库主机名
$dbName='test'; // 使用的数据库
$user='root'; // 数据库连接用户名
$pass='root'; // 对应的密码
$dsn="$dbms:host=$host;dbname=$dbName";

$db = new PDO($dsn, $user, $pass);

$sql = "SELECT * FROM role WHERE nick=:nick";
$stmt = $db->prepare($sql);
$nick = "demo'; DROP TABLE role;";
$stmt->execute(array('nick'=>$nick));
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($data);

开启了mysql操作日志 general_log、general_log_file 可以看到最终的执行语句是:

SELECT * FROM role WHERE nick='demo\'; DROP TABLE role;'

校验注入字符接口

我们也可以简单的写一个接口,检查数据是否含有SQL注入的字符,如果存在则返回1,正常返回0

function inject_check($sql_str) {
    return preg_match('/^select|insert|and|or|create|update|delete|alter|count|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile/i', $sql_str); // 进行过滤
}
echo inject_check("demo'; DROP TABLE role;");

参考资料:https://yq.aliyun.com/articles/42418#