热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

php操作mysql防止sql注入(合集)

本文将从sql注入风险说起,并且比较addslashes、mysql_escape_string、mysql_real_escape_string、mysqli和pdo的预处理的区别。
本文将从sql注入风险说起,并且比较addslashes、mysql_escape_string、mysql_real_escape_string、mysqli和pdo的预处理的区别,提供最好的防注入方法?

当一个变量从表单传入到php,需要查询mysql的话,需要进行处理。
举例:
$unsafe_variable = $_POST['user_input']; 
mysqli_query("INSERT INTO table (column) VALUES ('" . $unsafe_variable . "')"); 
用户可以输入诸如 : value'); DROP TABLE table; ,SQL语句就变成这样了:
INSERT INTO table (column) VALUES('value'); DROP TABLE table;') 
执行的结果就是table表被删掉了。

这是一种常见的sql注入方法,那么在程序中,应该怎样预防呢?

1.魔术引用 (推荐指数3)
addslashes()与stripslashes()是功能相反的函数。
addslashes()用于对变量中的' " \和NULL添加\斜杠,用于避免传入sql语句的参数格式错误,同时如果有人注入子查询,通过加\可以将参数解释为内容,而非执行语句,避免被mysql执行。

不过,addslashes()添加的\只在php中使用,并不会写入mysql中。
那么,tripslashes()的作用是将加了\的php变量\去掉,由于\不会写入mysql中,所以从mysql查询出来的内容不需要再tripslashes()。

在防注入方面,addslashes()可以防止掉大多数的注入,但是此函数并不会检查变量的编码,当使用例如中文gbk的时候,由于长度比较长 ,会将某些gbk编码解释成两个ascii编码,造成新的注入风险。见下面2。

如果从网页表单、php、mysql都使用utf8编码,则没有这个问题。
基于此函数的风险,并不建议使用,推荐使用下面3中的方法。
参考:https://segmentfault.com/q/1010000005994443


2. mysql_real_escape_string() (推荐指数4)
由于addslashes()不检测字符集,所以有宽字节注入风险,所以php中添加了这个函数。
这个函数本来是mysql的扩展,但是由于存在宽字节的问题,php基于mysql的扩展开发了此函数。

gbk宽字符漏洞导致的sql注入
参考:https://www.91ri.org/8611.html
参考:http://www.cnblogs.com/suihui/archive/2012/09/20/2694751.html

mysql_real_escape_chars()是mysql_escape_chars()的替代用法。
与addslashes()相比,不仅会将' " \ NOL(ascii的0)转义,还会把\r \n进行转义。同时会检测数据编码。
按php官方的描述,此函数可以安全的用于mysql。

此函数在使用时会使用于数据库连接(因为要检测字符集),并根据不同的字符集做不同的操作。如果当前连接不存在,刚会使用上一次的连接。

mysql_real_escape_string()防注入详解
此方法在php5.5后不被建议使用,在php7中废除。
参考:https://segmentfault.com/q/1010000006015688


3.预处理查询 (Prepared Statements) (推荐指数5)
使用prepared statements(预处理语句)和参数化的查询,可以有效的防止sql注入。

为什么预处理和参数化查询可以防止sql注入呢?
在传统的写法中,sql查询语句在程序中拼接,防注入(加斜杠)是在php中处理的,然后就发语句发送到mysql中,mysql其实没有太好的办法对传进来的语句判断哪些是正常的,哪些是恶意的,所以直接查询的方法都有被注入的风险。
在mysql5.1后,提供了类似于jdbc的预处理参数化查询。它的查询方法是:
a. 先预发送一个sql模板过去
b. 再向mysql发送需要查询的参数
就好像填空题一样,不管参数怎么注入,mysql都能知道这是变量,不会做语义解析,起到防注入的效果,这是在mysql中完成的。

参考:
PHP中如何防止SQL注入 
http://blog.csdn.net/sky_zhe/article/details/9702489

参数化查询为什么能够防止SQL注入
http://www.cnblogs.com/LoveJenny/archive/2013/01/15/2860553.html


上面提供的资料比较多,下面根据自己的理解整理出来。

预处理分为两种:
A.使用mysqli:prepare()实现
看一个完整的用法:
$mysqli = new mysqli("example.com", "user", "password", "database");
$stmt = $mysqli>prepare("SELECT id, label FROM test WHERE id = ?");
$stmt>bind_param(1, $city);
$stmt>execute();
$res = $stmt>get_result();
$row = $res>fetch_assoc();

a.写sql语句,然后用?占位符替代sql中的变量
b.替换变量
c.执行
d.得到一个二进制结果集,从二进制结果中取出php结果集
e.遍历结果集

使用预处理,一条查询分两步,先是,所以很安全。也是php5.5及php7推荐方法。

参考:
http://www.cnblogs.com/liuzhang/p/4753467.html


B. 使用pdo实现
pdo是一个php官方推荐的数据库抽象层,提供了很多实用的工具。

使用pdo的预处理参数化查询可以有效防止sql注入。
使用方法跟上面差不多,区别在于pdo提供了更多样的方法。
使用这个pdo>$stmt对象进行查询后,会被结果集覆盖,类型是一个二维数组。

我们在上面预处理参数化查询是在mysql中进行防注入操作的,其实pdo也内置了一个预处理的模拟器,叫做ATTR_EMULATE_PREPARES。
默认情况下,PDO会使用DSN中指定的字符集对输入参数进行本地转义(PHP手册中称为native prepared statements),然后拼接成完整的SQL语句,发送给MySQL Server。这有些像我们平时程序中拼接变量到SQL再执行查询的形式。

这种情况下,PDO驱动能否正确转义输入参数,是拦截SQL注入的关键。然而PHP 5.3.6及老版本,并不支持在DSN中定义charset属性(会忽略之),这时如果使用PDO的本地转义,仍然可能导致SQL注入,

如果ATTR_EMULATE_PREPARES=true(默认情况),预处理参数化查询在pdo的模拟器中完成,模拟器根据字符集(dsn参数)进行处理,然后把语句发送给mysql。

如果ATTR_EMULATE_PREPARES=false,sql会分两次把参数给送给mysql,mysql根据自身的字符集(set names )进行处理,完成查询。

但由于各版本差异,pdo在各版本中的实现程度也不一样,有些版本还有bug,我们以php5.3.6做为分界线来进行说明:

php5.3.6以下版本
$pdo = new PDO("mysql:host=localhost;dbname=test;",'root','pwd');
$pdo>setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
$pdo>exec('set names utf8');
$id = '0 or 1 =1 order by id desc';
$sql = "select from article where id = ?";
$statement = $pdo>prepare($sql);
$statement>bindParam(1, $id);
$statement>execute();
如上,我们关闭了本地预处理模拟器,参数会直接分批发送给mysql,由mysql根据set name utf8字符集进行检测,完成sql注入处理。以上代码不会产生注入。

php5.3.6以上版本
$pdo = new PDO("mysql:host=localhost;dbname=test;charset=utf8",'root','pwd');
$pdo>exec('set names utf8');
$id = '0 or 1 =1 order by id desc';
$sql = "select from article where id = ?";
$statement = $pdo>prepare($sql);
$statement>bindParam(1, $id);
$statement>execute();
在php5.3.6以上版本中,默认情况下ATTR_EMULATE_PREPARES开启,模拟器会根据new PDO()中的charset=utf8进行检测,在模拟器上完成防注入操作。如果把模拟器关闭,也会像低版本一样送交mysql进行防注入处理。

参考:
PDO防注入原理分析以及使用PDO的注意事项
http://zhangxugg163com.iteye.com/blog/1835721


PHP 5.3.6及以前版本的PDO的bindParam,bindValue潜在的安全隐患
http://zhangxugg163com.iteye.com/blog/1855088

再论php 5.3.6以前版本中的PDO SQL注入漏洞问题
http://my.oschina.net/zxu/blog/163135

segmentfault讨论
https://segmentfault.com/q/1010000000723496



4. html输出与防止xss注入

特殊字符输出
比如' " <>有着特殊的意义,如果直接写到html中输出,会引起dom格式的错乱,那么就需要用到特殊的输出方法。


推荐阅读
  • ABP框架是ASP.NET Boilerplate的简称,它不仅是一个开源且文档丰富的应用程序框架,还提供了一套基于领域驱动设计(DDD)的最佳实践架构模型。本文将详细介绍ABP框架的特点、项目结构及其在Web API优先架构中的应用。 ... [详细]
  • 本文详细探讨了在Web开发中常见的UTF-8编码问题及其解决方案,包括HTML页面、PHP脚本、MySQL数据库以及JavaScript和Flash应用中的乱码问题。 ... [详细]
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 如何将955万数据表的17秒SQL查询优化至300毫秒
    本文详细介绍了通过优化SQL查询策略,成功将一张包含955万条记录的财务流水表的查询时间从17秒缩短至300毫秒的方法。文章不仅提供了具体的SQL优化技巧,还深入探讨了背后的数据库原理。 ... [详细]
  • 龙蜥社区开发者访谈:技术生涯的三次蜕变 | 第3期
    龙蜥社区的开发者们通过自己的实践和经验,推动着开源技术的发展。本期「龙蜥开发者说」聚焦于一位资深开发者的三次技术转型,分享他在龙蜥社区的成长故事。 ... [详细]
  • 最新版 EasyCriteria 3.0 已正式上线,该版本经过全面重构,带来了多项性能优化与功能增强。更多详情请参阅官方文档:http://uaihebert.com/?p=1898 ... [详细]
  • Markdown 编辑技巧详解
    本文介绍如何使用 Typora 编辑器高效编写 Markdown 文档,包括代码块的插入方法等实用技巧。Typora 官方网站:https://www.typora.io/ 学习资源:https://www.markdown.xyz/ ... [详细]
  • 本文介绍了ADO.NET框架中的五个关键组件:Connection、Command、DataAdapter、DataSet和DataReader。每个组件都在数据访问和处理过程中扮演着不可或缺的角色。 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
  • Windows操作系统提供了Encrypting File System (EFS)作为内置的数据加密工具,特别适用于对NTFS分区上的文件和文件夹进行加密处理。本文将详细介绍如何使用EFS加密文件夹,以及加密过程中的注意事项。 ... [详细]
  • 回顾两年前春节期间的一个个人项目,该项目原本计划参加竞赛,但最终作为练习项目完成。独自完成了从编码到UI设计的全部工作,尽管代码量不大,但仍有一定的参考价值。本文将详细介绍该项目的背景、功能及技术实现。 ... [详细]
  • 在编程实践中,正确管理和释放资源是非常重要的。本文将探讨 Python 中的 'with' 关键字及其背后的上下文管理器机制,以及它们如何帮助我们更安全、高效地管理资源。 ... [详细]
  • 解决Win7系统下MySQL安装时的安全设置应用失败问题
    本文详细探讨了在Windows 7操作系统中安装MySQL时遇到的‘安全设置无法应用于数据库’错误的解决方案。通过逐步指导和专业建议,帮助用户顺利解决这一常见问题。 ... [详细]
  • Vulnhub DC3 实战记录与分析
    本文记录了在 Vulnhub DC3 靶机上的渗透测试过程,包括漏洞利用、内核提权等关键步骤,并总结了实战经验和教训。 ... [详细]
  • 本文详细探讨了如何在PHP中有效防止SQL注入攻击,特别是在使用MySQL数据库时。文章通过具体示例和专业建议,帮助开发者理解和应用最佳实践。 ... [详细]
author-avatar
Kluter
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有