在PHP中全面阻止SQL注入式攻击之三
一、 建立一个安全抽象层
我们并不建议你手工地把前面介绍的技术应用于每一个用户输入的实例中,而是强烈推荐你为此创建一个抽象层。一个简单的抽象是把你的校验方案加入到一个函数中,并且针对用户输入的每一项调用这个函数。当然,我们还可以创建一种更复杂的更高一级的抽象-把一个安全的查询封装到一个类中,从而应用于整个应用程序。在网上已经存在许多这种现成的免费的类;在本篇中,我们正要讨论其中的一些。
进行这种抽象至少存在三个优点(而且每一个都会改进安全级别):
1. 本地化代码。
2. 使查询的构造更快且更为可靠-因为这可以把部分工作交由抽象代码来实现。
3. 当基于安全特征进行构建并且恰当使用时,这将会有效地防止我们前面所讨论的各种各样的注入式攻击。
二、 改进现有的应用程序
如果你想改进一个现有的应用程序,则使用一个简单的抽象层是最适当的。一个能够简单地"清理"你所收集的任何用户输入内容的函数可能看起来如下所示:
function safe( $string ) { return "'" . mysql_real_escape_string( $string ) . "'" } |
【注意】我们已经构建了相应于值要求的单引号以及mysql_real_escape_string()函数。接下来,就可以使用这个函数来构造一个$query变量,如下所示:
$variety = safe( $_POST['variety'] ); $query = " SELECT * FROM wines WHERE variety=" . $variety; |
现在,你的用户试图进行一个注入式攻击-通过输入下列内容作为变量$variety的值:
lagrein' or 1=1; |
注意,如果不进行上面的"清理",则最后的查询将如下所示(这将导致无法预料的结果):
SELECT * FROM wines WHERE variety = 'lagrein' or 1=1;' |
然而现在,既然用户的输入已经被清理,那么查询语句就成为下面这样一种无危害的形式:
SELECT * FROM wines WHERE variety = 'lagrein/' or 1=1/;' |
既然数据库中不存在与指定的值相应的variety域(这正是恶意用户所输入的内容-lagrein' or 1=1;),那么,这个查询将不能返回任何结果,并且注入将会失败。
三、 保护一个新的应用程序
如果你正在创建一个新的应用程序,那么,你可以从头开始创建一个安全抽象层。如今,PHP 5新改进的对于MySQL的支持(这主要体现在新的mysqli扩展中)为这种安全特征提供了强有力的支持(既有过程性的,也有面向对象特征的)。你可以从站点http://php.net/mysqli上获取有关mysqli的信息。注意,只有当你使用--with-mysqli=path/to/mysql_config选项编译PHP时,这种mysqli支持才可用。下面是该代码的一个过程性版本,用于保护一个基于mysqli的查询:
<?php //检索用户的输入 $animalName = $_POST['animalName']; //连接到数据库 $connect = mysqli_connect( 'localhost', 'username', 'password', 'database' ); if ( !$connect ) exit( 'connection failed: ' . mysqli_connect_error() ); //创建一个查询语句源 $stmt = mysqli_prepare( $connect,"SELECT intelligence FROM animals WHERE name = ?" ); if ( $stmt ) { //把替代绑定到语句上 mysqli_stmt_bind_param( $stmt, "s", $animalName ); //执行该语句 mysqli_stmt_execute( $stmt ); //检索结果... mysqli_stmt_bind_result( $stmt, $intelligence ); // ...并显示它 if ( mysqli_stmt_fetch( $stmt ) ) { print "A $animalName has $intelligence intelligence./n"; } else { print 'Sorry, no records found.'; } //清除语句源 mysqli_stmt_close( $stmt ); } mysqli_close( $connect ); ?> |
该mysqli扩展提供了一组函数用于构造和执行查询。而且,它也非常准确地提供了前面使用我们自己的safe()函数所实现的功能。
在上面的片断中,首先收集用户提交的输入内容并建立数据库连接。然后,使用mysqli_prepare()函数创建一个查询语句源-在此命名为$stmt以反映使用它的函数的名称。这个函数使用了两个参数:连接资源和一个字符串(每当你使用扩展插入一个值时,"?"标记被插入到其中)。在本例中,你仅有一个这样的值-动物的名字。
注意,在一个SELECT语句中,放置"?"标记的唯一的有效位置是在值比较部分。这正是为什么你不需要指定使用哪个变量的原因(除了在mysqli_stmt_bind_param()函数中之外)。在此,你还需要指定它的类型-在本例中,"s"代表字符串。其它可能的类型有:"I"代表整数,"d"代表双精度数(或浮点数),而"b"代表二进制字符串。
函数mysqli_stmt_execute(),mysqli_stmt_bind_result()和mysqli_stmt_fetch()负责执行查询并检索结果。如果存在检索结果,则显示它们;如果不存在结果,则显示一条无害的消息。最后,你需要关闭$stmt资源以及数据库连接-从内存中对它们加以释放。
假定一个合法的用户输入了字符串"lemming",那么这个例程将(假定是数据库中适当的数据)输出消息"A lemming has very low intelligence."。假定存在一个尝试性注入-例如"lemming' or 1=1;",那么这个例程将打印(无害)消息"Sorry, no records found."。
此外,mysqli扩展还提供了一个面向对象版本的相同的例程。下面,我们想说明这种版本的使用方法。
<?php $animalName = $_POST['animalName']; $mysqli = new mysqli( 'localhost', 'username', 'password', 'database'); if ( !$mysqli ) exit( 'connection failed: ' . mysqli_connect_error() ); $stmt = $mysqli->prepare( "SELECT intelligence FROM animals WHERE name = ?" ); if ( $stmt ) { $stmt->bind_param( "s", $animalName ); $stmt->execute(); $stmt->bind_result( $intelligence ); if ( $stmt->fetch() ) { print "A $animalName has $intelligence intelligence./n"; } else { print 'Sorry, no records found.'; } $stmt->close(); } $mysqli->close(); ?> |
实际上,这部分代码是前面描述代码的复制-它使用了一种面向对象的语法和组织方法,而不是严格的过程式代码。
四、 更高级的抽象
如果你使用外部库PearDB,那么,你可以对应用程序的安全保护模块进行全面的抽象。
另一方面,使用这个库存在一个突出的缺点:你只能受限于某些人的思想,而且代码管理方面也添加了大量的工作。为此,在决定是否使用它们之前,你需要进行仔细地斟酌。如果你决定这样做,那么,你至少确保它们能够真正帮助你"清理"你的用户输入的内容。
五、 测试你的注入式保护能力
正如我们在前面所讨论的,确保你的脚本安全的一个重要的部分是对它们进行测试。为此,最好的办法是你自己创建SQL代码注入测试。
在此,我们提供了一个这种测试的示例。在本例中,我们测试对一个SELECT语句的注入式攻击。
<?php //被测试的保护函数 function safe( $string ) { return "'" . mysql_real_escape_string( $string ) . "'" } //连接到数据库 /// //试图进行注入 /// $exploit = "lemming' AND 1=1;"; //进行清理 $safe = safe( $exploit ); $query = "SELECT * FROM animals WHERE name = $safe"; $result = mysql_query( $query ); //测试是否保护是足够的 if ( $result && mysql_num_rows( $result ) == 1 ) { exitt "Protection succeeded:/n exploit $exploit was neutralized."; } else { exit( "Protection failed:/n exploit $exploit was able to retrieve all rows." ); } ?> |
如果你想创建这样的一个测试集,并试验基于不同的SQL命令的各种不同的注入,那么,你将会很快地探测出你的保护策略中的任何漏洞。一旦纠正这些问题,那么,你就可以很有把握-你已经建立起真正的注入式攻击保护机制。
六、 小结
在本系列文章一开始,我们通过一个SQL注入讨论分析了对你的脚本的特定威胁-由不恰当的用户输入所致。之后,我们描述了SQL注入的工作原理并精确地分析了PHP是怎样易于被注入的。然后,我们提供了一个实际中的注入示例。之后,我们推荐一系列措施来使试图的注入攻击变为无害的-这将分别通过确保使所有提交的值以引号封闭,通过检查用户提交值的类型,以及通过过滤掉你的用户输入的潜在危险的字符等方法来实现的。最后,我们推荐,你最好对你的校验例程进行抽象,并针对更改一个现有应用程序提供了脚本示例。然后,我们讨论了第三方抽象方案的优缺点。
在PHP中全面阻止SQL注入式攻击之三相关推荐
- php阻止输入sql,在PHP中全面阻止SQL注入式攻击之三
一. 建立一个安全抽象层 我们并不建议你手工地把前面介绍的技术应用于每一个用户输入的实例中,而是强烈推荐你为此创建一个抽象层.一个简单的抽象是把你的校验方案加入到一个函数中,并且针对用户输入的每一项调 ...
- ASP.NET中如何防范SQL注入式攻击
1将sql中使用的一些特殊符号,如' -- /* ; %等用Replace()过滤: 2限制文本框输入字符的长度: 3检查用户输入的合法性:客户端与服务器端都要执行,可以使用正则. 4使用带参数的SQ ...
- [ZT]ASP.NET中如何防范SQL注入式攻击
所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存 ...
- Sql注入式攻击和一些防范技巧
这篇文章原文出自www.codeproject.com,因个人喜欢,做了点翻译,但是本人英语水平实在太菜,翻译中可能错误百出,如果误导大家,实在抱歉.所以建议大家还是去看原版,地址为:http://w ...
- 【转载】防范SQL注入式攻击
SQL注入式攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql命令以及进行其他方式的攻击动态生成Sql命令时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因. 比如: 如果你的查询语句 ...
- 防止SQL注入式攻击的笔记
SQL注入式攻击是指利用设计上的漏洞攻击系统.如果动态生成SQL语句时没有对用户输入的数据 进行过滤,便会使SQL注入式攻击得逞. 例如用下面的SQL语句判断用户名和密码: txtsql=" ...
- 防范SQL注入式攻击
SQL注入式攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql命令以及进行其他方式的攻击动态生成Sql命令时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因. 比如: 如果你的查询语句 ...
- 什么是SQL注入式攻击!如何防范SQL注入式攻击?
1.所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令. 2.在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令 ...
- 什么是SQL注入式攻击,如何去防范SQL注入式攻击
1.SQL注入式攻击 所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令.比如:攻击者在用户名字和密码输入框中输入"' ...
最新文章
- mysql 统计做饼状图_PHP+mysql+Highcharts实现饼状统计图
- php设计模式八-----装饰器模式
- LOJ#6044. 「雅礼集训 2017 Day8」共(Prufer序列)
- 2018华为软件精英挑战赛总结
- smarty调试方法
- Android复习09【内容提供者、音乐播放器(附完整工程文件)】
- C++:27---new delete malloc free
- php 去掉后导字符,PHP去除字符串最后一个字符的三种方法实例
- 1. DFT 入门篇-scan chain
- CSS3---渲染属性
- 梦笔记2022-2-10
- 薛定谔 Maestro教程--用户界面 | 结构编辑 | 测量距离角度
- Python+OpenCV实现sobel边缘检测
- 使用工具YUMI制作多系统启动盘
- HZD区块链导航网站好站点,你知道的都在这里
- 联想小新 Pro 14、联想小新 Pro 16 2023 酷睿版 评测 怎么样值得买吗
- 2019年实习过的同学来领钱啦!我可以退4000多!附:退税攻略
- ai是个什么软件,和PS一样么
- 机器学习必须需要大量数据?小数据集也能有大价值!
- vue中使用微信jssdk语音聊天功能,实现语音输入内容的van-field输入框组件
热门文章
- Unity计时器功能
- Binding的学习与使用
- linux2017期末试卷,LINUX认证考试模拟试题及答案
- 计算机学院品牌活动,计算机学院研究生会举办十佳健康品牌活动
- I2S总线学习:I2S数据格式
- java 修改图片名_Java修改文件夹下图片的名称
- AVProVideo☀️九、“今朝若能同淋雪,此生也算共白头”。一曲《南山雪》,学习给视频做字幕。
- 2022电大国家开放大学网上形考任务-建筑工程项目管理非免费(非答案)
- 笨办法学python 习题46-windows
- 【AE工具】AE一键切换中英文小工具,免费下载 支持CC2014-CC2019