Web 安全 - SQL注入
原文链接 https://kevindiamen.github.io/web%E5%AE%89%E5%85%A8/2017/01/11/Web%E5%AE%89%E5%85%A8-Sql%E6%B3%A8%E5%85%A5.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
Web 安全 - SQL注入
介绍
SQL注入攻击(SQL Injection), 是由于程序没有过滤恶意提交的SQL查询,最终达到欺骗服务器执行恶意的SQL命令
SQL注入案例
如果直接拼接 SQL 而没有进行任何处理, 像下面这样就会有恶意的用户输入导致改变你的 SQL queries
mysql_query('UPDATE users SET first_name="' . $_POST['first_name'] . '"
WHERE id=1001');
你期望生成的SQL:
UPDATE users set first_name="Liz" WHERE id=1001;
但是如果恶意的用户 first_name 的值为:
Liz", last_name="Lemon"; --
最终的 SQL 变成:
UPDATE users SET first_name="Liz", last_name="Lemon"; --" WHERE id=1001;
现在所有的 users 表中名字为 Liz Lemon 的就会查询出来
SQL注入防御
绑定参数
一个比较好的并且简单的方法就是绑定参数的方法, 用绑定参数的每个值将会被转义并且也会忽略掉编码问题, 不要用拼接SQL的方法这样已经被证实并不安全, 也不建议用 addslashes() 方法, 因为在 Mysql5.5 之前 可以通过编码单字节双字节问题进行绕过, 下面是PHP的PDO class.
绑定参数 Mysql 会创建 sql语句模板,并发送到数据库。预留的值使用参数 ? 标记数据库对模板解析,编译,对sql 语句模板执行查询优化 ,预处理语句能很好的防止 sql注入,因为参数的发送不会影响一开始对模板的解析,编译。
$db = new PDO(...);
$query = $db->prepare('UPDATE users SET first_name = :first_name WHERE id = :id');
$query->execute([
':first_name' => $_POST['first_name']
]);
- 输出处理 : 虽然绑定参数可以保护你的query 但是数据可能是恶意的 所以你显示给用户的时候还需要做处理
- 过滤参数 : 比如手机号 邮箱可以用正则表达式匹配, PHP 建议使用 filter_ var() 和 filter_input() 函数可以过滤文本并对格式进行校验
存储过程
存储过程是另一个方法去避免SQL注入, 他是一组完成特定功能的SQL,经过编译后存储在数据库中, 但是存储过程比较麻烦主要有几点原因:
- 调试麻烦
- 移植问题
- 逻辑在另一个应用上