PHP中防止SQL注入方法详解


Posted in PHP onDecember 25, 2014

问题描述:

如果用户输入的数据在未经处理的情况下插入到一条SQL查询语句,那么应用将很可能遭受到SQL注入攻击,正如下面的例子:

$unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('" . $unsafe_variable . "')");

因为用户的输入可能是这样的:

value'); DROP TABLE table;--

那么SQL查询将变成如下:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

应该采取哪些有效的方法来防止SQL注入?

 最佳回答(来自Theo):

使用预处理语句和参数化查询。预处理语句和参数分别发送到数据库服务器进行解析,参数将会被当作普通字符处理。这种方式使得攻击者无法注入恶意的SQL。 你有两种选择来实现该方法:

1、使用PDO:

$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');

 

$stmt->execute(array('name' => $name));

 

foreach ($stmt as $row) {

    // do something with $row

}

2、使用mysqli:

$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');

$stmt->bind_param('s', $name);

 

$stmt->execute();

 

$result = $stmt->get_result();

while ($row = $result->fetch_assoc()) {

    // do something with $row

}

 PDO

注意,在默认情况使用PDO并没有让MySQL数据库执行真正的预处理语句(原因见下文)。为了解决这个问题,你应该禁止PDO模拟预处理语句。一个正确使用PDO创建数据库连接的例子如下:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

在上面的例子中,报错模式(ATTR_ERRMODE)并不是必须的,但建议加上它。这样,当发生致命错误(Fatal Error)时,脚本就不会停止运行,而是给了程序员一个捕获PDOExceptions的机会,以便对错误进行妥善处理。 然而,第一个setAttribute()调用是必须的,它禁止PDO模拟预处理语句,而使用真正的预处理语句,即有MySQL执行预处理语句。这能确保语句和参数在发送给MySQL之前没有被PHP处理过,这将使得攻击者无法注入恶意SQL。了解原因,可参考这篇博文:PDO防注入原理分析以及使用PDO的注意事项。 注意在老版本的PHP(<5.3.6),你无法通过在PDO的构造器的DSN上设置字符集,参考:silently ignored the charset parameter。

 解析

当你将SQL语句发送给数据库服务器进行预处理和解析时发生了什么?通过指定占位符(一个?或者一个上面例子中命名的 :name),告诉数据库引擎你想在哪里进行过滤。当你调用execute的时候,预处理语句将会与你指定的参数值结合。 关键点就在这里:参数的值是和经过解析的SQL语句结合到一起,而不是SQL字符串。SQL注入是通过触发脚本在构造SQL语句时包含恶意的字符串。所以,通过将SQL语句和参数分开,你防止了SQL注入的风险。任何你发送的参数的值都将被当作普通字符串,而不会被数据库服务器解析。回到上面的例子,如果$name变量的值为 'Sarah'; DELETE FROM employees ,那么实际的查询将是在 employees 中查找 name 字段值为 'Sarah'; DELETE FROM employees 的记录。 另一个使用预处理语句的好处是:如果你在同一次数据库连接会话中执行同样的语句许多次,它将只被解析一次,这可以提升一点执行速度。 如果你想问插入该如何做,请看下面这个例子(使用PDO):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute(array('column' => $unsafeValue));
PHP 相关文章推荐
PHP中文汉字验证码
Apr 08 PHP
收藏的一个php小偷的核心程序
Apr 09 PHP
php google或baidu分页代码
Nov 26 PHP
php实现首页链接查询 友情链接检查的代码
Jan 05 PHP
php 自写函数代码 获取关键字 去超链接
Feb 08 PHP
需要注意的几个PHP漏洞小结
Feb 05 PHP
php 使用file_get_contents读取大文件的方法
Nov 13 PHP
yiic命令时提示“php.exe”不是内部或外部命令的解决方法
Dec 18 PHP
教你识别简单的免查杀PHP后门
Sep 13 PHP
PHP面试题之文件目录操作
Oct 15 PHP
php版阿里大于(阿里大鱼)短信发送实例详解
Nov 30 PHP
PHP编程一定要改掉的5个不良习惯
Sep 18 PHP
使用PHP实现阻止用户上传成人照片或者裸照
Dec 25 #PHP
浅析PHP文件下载原理
Dec 25 #PHP
php使用sql server验证连接数据库的方法
Dec 25 #PHP
php实现mysql事务处理的方法
Dec 25 #PHP
php使用pdo连接mssql server数据库实例
Dec 25 #PHP
php连接与操作PostgreSQL数据库的方法
Dec 25 #PHP
完整删除ecshop中获取店铺信息的API
Dec 24 #PHP
You might like
PHP error_log()将错误信息写入一个文件(定义和用法)
2013/10/25 PHP
php生成EAN_13标准条形码实例
2013/11/13 PHP
php include类文件超时问题处理
2015/02/06 PHP
简单了解PHP编程中数组的指针的使用
2015/11/30 PHP
php实现将HTML页面转换成word并且保存的方法
2016/10/14 PHP
CodeIgniter整合Smarty的方法详解
2017/08/25 PHP
PHP封装的XML简单操作类完整实例
2017/11/13 PHP
Code:loadScript( )加载js的功能函数
2007/02/02 Javascript
你需要知道的JavsScript可以做什么?
2007/06/29 Javascript
jquery网页元素拖拽插件效果及实现
2013/08/05 Javascript
javascript实现滑动解锁功能
2014/12/31 Javascript
js字符串截取函数slice、substring和substr的比较
2016/05/17 Javascript
javascript实现抽奖程序的简单实例
2016/06/07 Javascript
BootStrap中Table分页插件使用详解
2016/10/09 Javascript
javascript实现无法关闭的弹框
2016/11/27 Javascript
vue2.0实战之使用vue-cli搭建项目(2)
2017/03/27 Javascript
微信小程序 连续旋转动画(this.animation.rotate)详解
2017/04/07 Javascript
angular使用bootstrap方法手动启动的实例代码
2017/07/18 Javascript
JavaScript模板引擎实现原理实例详解
2018/12/14 Javascript
Vue开发之封装分页组件与使用示例
2019/04/25 Javascript
JS数组扁平化、去重、排序操作实例详解
2020/02/24 Javascript
Python素数检测的方法
2015/05/11 Python
python模块之paramiko实例代码
2018/01/31 Python
使用Python的Dataframe取两列时间值相差一年的所有行方法
2018/07/10 Python
python实现多张图片拼接成大图
2019/01/15 Python
解决Python 函数声明先后顺序出现的问题
2020/09/02 Python
Myprotein蛋白粉美国官网:欧洲畅销运动营养品牌
2016/11/15 全球购物
Perfume’s Club德国官网:在线购买香水
2019/04/08 全球购物
欧缇丽加拿大官方网站:Caudalie加拿大
2019/07/18 全球购物
员工拾金不昧表扬信
2014/01/09 职场文书
经典的毕业生自荐信范文
2014/04/14 职场文书
电信营业员岗位职责
2015/04/14 职场文书
房产销售员2015年终工作总结
2015/10/22 职场文书
2016关于学习党章的心得体会
2016/01/15 职场文书
MySQL提升大量数据查询效率的优化神器
2022/07/07 MySQL
Python 第三方库 openpyxl 的安装过程
2022/12/24 Python