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 相关文章推荐
JSON在PHP中的应用介绍
Sep 08 PHP
深入理解用mysql_fetch_row()以数组的形式返回查询结果
Jun 05 PHP
php使用ICQ网关发送手机短信
Oct 30 PHP
在Yii框架中使用PHP模板引擎Twig的例子
Jun 13 PHP
PHP的error_reporting错误级别变量对照表
Jul 08 PHP
百度实时推送api接口应用示例
Oct 21 PHP
PHP使用xmllint命令处理xml与html的方法
Dec 15 PHP
讲解WordPress中用于获取评论模板和搜索表单的PHP函数
Dec 28 PHP
php生成0~1随机小数的方法(必看)
Apr 05 PHP
使用PHP连接数据库_实现用户数据的增删改查的整体操作示例
Sep 01 PHP
CodeIgniter整合Smarty的方法详解
Aug 25 PHP
PHP实现字符串翻转功能的方法【递归与循环算法】
Nov 03 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中怎么搜索相关联数组键值及获取之
2013/10/17 PHP
在Windows XP下安装Apache+MySQL+PHP环境
2015/02/22 PHP
ThinkPHP中Common/common.php文件常用函数功能分析
2016/05/20 PHP
js 时间函数应用加、减、比较、格式转换的示例代码
2013/08/23 Javascript
jquery.autocomplete修改实现键盘上下键自动填充示例
2013/11/19 Javascript
在JavaScript中判断整型的N种方法示例介绍
2014/06/18 Javascript
js实现按一下删除键删除整个单词附demo
2014/09/05 Javascript
KnockoutJS 3.X API 第四章之数据控制流foreach绑定
2016/10/10 Javascript
详解前端构建工具gulpjs的使用介绍及技巧
2017/01/19 Javascript
微信小程序template模板实例详解
2017/10/27 Javascript
实例教学如何写vue插件
2017/11/30 Javascript
React native ListView 增加顶部下拉刷新和底下点击刷新示例
2018/04/27 Javascript
jQuery实现的鼠标拖动画矩形框示例【可兼容IE8】
2019/05/17 jQuery
手把手教你 CKEDITOR 4 实现Dialog 内嵌 IFrame操作详解
2019/06/18 Javascript
如何换个角度使用VUE过滤器详解
2019/09/11 Javascript
解决vue项目中某一页面不想引用公共组件app.vue的问题
2020/08/14 Javascript
js实现批量删除功能
2020/08/27 Javascript
Python中if __name__ == &quot;__main__&quot;详细解释
2014/10/21 Python
python删除过期文件的方法
2015/05/29 Python
对Python中range()函数和list的比较
2018/04/19 Python
Python爬虫小技巧之伪造随机的User-Agent
2018/09/13 Python
python3利用Socket实现通信的方法示例
2019/05/06 Python
不可轻视HTML5!App三年内将被html5顶替彻底消失
2015/11/18 HTML / CSS
如何在Canvas上的图形/图像绑定事件监听的实现
2020/09/16 HTML / CSS
英国豪华文具和皮具配件经典老品牌:Smythson(斯迈森)
2018/04/19 全球购物
Java基础面试题
2012/11/02 面试题
超市总经理岗位职责
2014/02/02 职场文书
致跳高运动员加油稿
2014/02/12 职场文书
纠纷协议书
2014/04/16 职场文书
美食节策划方案
2014/05/26 职场文书
奥林匹克的口号
2014/06/13 职场文书
2014国庆节标语口号
2014/09/19 职场文书
捐助倡议书
2015/01/19 职场文书
大学军训通讯稿
2015/07/18 职场文书
小学生班干部竞选稿
2015/11/20 职场文书
Redis延迟队列和分布式延迟队列的简答实现
2021/05/13 Redis