PDO预处理防御SQL注入

PDO预处理防御SQL注入PDO 可以被认作是一种通过编译 SQL 语句模板来运行 SQL 语句的机制 查询仅需解析 或预处理 一次 但可以用相同或不同的参数执行多次 当查询准备好后 数据库将分析 编译和优化执行该查询的计划 对于复杂的查询 此过程要花费较长的时间 如果需要以不同参数多次重复相同的查询

大家好,我是讯享网,很高兴认识大家。

PDO可以被认作是一种通过编译SQL语句模板来运行SQL语句的机制。

  • 查询仅需解析(或预处理)一次,但可以用相同或不同的参数执行多次。当查询准备好后,数据库将分析、编译和优化执行该查询的计划。对于复杂的查询,此过程要花费较长的时间,如果需要以不同参数多次重复相同的查询,那么该过程将大大降低应用程序的速度。通过使用预处理语句,可以避免重复分析/编译/优化周期。简言之,预处理语句占用更少的资源,因而运行得更快。
  • 提供给预处理语句的参数不需要用引号括起来,驱动程序会自动处理。如果应用程序只使用预处理语句,可以确保不会发生SQL注入。(然而,如果查询的其他部分是由未转义的输入来构建,则仍存在SQL注入的风险)。

示例1,如下为一个简易的PDO预处理查询环境

<link.php>

<?php $servername="localhost"; $username="root"; $password="root"; $database="test"; $link =new PDO("mysql:host=$servername;dbname=$database",$username,$password); $stmt=$link->prepare('select * from users where id=?'); $stmt->execute([$_GET['id']]); foreach ($stmt as $item) { echo $item['id'].'&nbsp'; echo $item['name'].'&nbsp'; echo $item['sex'].'&nbsp'; echo $item['passwd'].'&nbsp'; } 

讯享网

通过一个简易html页面提交id参数

讯享网<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>pdo-test</title>
</head>
<body>
<form action="link.php" method="get">
    <input name="id" type="text">
    <input name="submit" type="submit">

</form>

</body>
</html>

测试数据表users


讯享网

 提交敏感字符进行查询并查看日志记录,发现对 ' " 进行了转义处理,这就有点类似于addslashes()和mysql_real_escape_string()

 那可能会想到是否可以进行宽字节注入,使用payload:%df ' or 1=1#一试便知

 答案是当然不可以。宽字节注入需要满足两个条件:1、数据库连接使用宽字符集。2、使用转义函数来过滤输入的敏感字符。

这就涉及到PDO的转义机制

  • 本地转义,使用单字节字符集(PHP<5.3.6)来对输入进行转义,但这种方式存在安全隐患。在PHP版本小于5.3.6时,本地转义只能转换单字节的字符集,大于5.3.6的版本会根据PDO连接中指定的字符集进行转义。
  • mysql服务端转义,首先将SQL语句模板发送到mysql server,而后再讲绑定的变量发送给mysql server,这里的转义在mysql server中完成,根据PDO连接中指定的字符集进行转义。这样的转义方式更健全,同时还可以在有多次重复查询的业务场景下,通过复用模板来提高程序的性能。如果使用此转义机制需要添加参数:$PDO->setAttribute(PDO::ATTR_EMULATE_PREPARES,false),此参数默认情况下为true。如果不修改该参数,PDO会将输入的参数使用本地转义后和sql语句模板拼接并发送至mysql server。

示例1为本地转义机制,示例2如下添加PDO::ATTR_EMULATE_PREPARES参数后看看效果:

<?php $servername="localhost"; $username="root"; $password="root"; $database="test"; $link =new PDO("mysql:host=$servername;dbname=$database",$username,$password); $link->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); $stmt=$link->prepare('select * from users where id=?'); $stmt->execute([$_GET['id']]); foreach ($stmt as $item) { echo $item['id'].'&nbsp'; echo $item['name'].'&nbsp'; echo $item['sex'].'&nbsp'; echo $item['passwd'].'&nbsp'; } 

执行刚才的payload后查看日志,比刚才多出了一条预处理语句,原因是数据库先对预处理语句模板进行了解析,再将绑定参数发送给服务端执行。

 本文只做参考,如有不当之处还请师傅们指正,要想更加深入理解PDO还请查阅PHP官方文档。

小讯
上一篇 2025-01-19 22:23
下一篇 2025-02-20 16:20

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/41526.html