如何防止 PHP 中的 SQL 注入?

2023-11-21

如果用户输入未经修改就插入到 SQL 查询中,则应用程序很容易受到攻击SQL注入,如以下示例所示:

$unsafe_variable = $_POST['user_input']; 

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

这是因为用户可以输入类似的内容value'); DROP TABLE table;--,查询变为:

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

可以采取什么措施来防止这种情况发生?


Answer recommended by PHP Collective

The correct无论您使用哪种数据库,避免 SQL 注入攻击的方法是将数据与 SQL 分离,这样数据就保持数据状态并且会永远不会被解释作为 SQL 解析器的命令。可以使用格式正确的数据部分创建 SQL 语句,但如果不这样做fully了解细节,你应该始终使用准备好的语句和参数化查询。这些是与任何参数分开发送到数据库服务器并由数据库服务器解析的 SQL 语句。这样攻击者就不可能注入恶意SQL。

基本上你有两种选择来实现这一目标:

  1. Using PDO(对于任何受支持的数据库驱动程序):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    $stmt->execute([ 'name' => $name ]);
    
    foreach ($stmt as $row) {
        // Do something with $row
    }
    
  2. Using MySQLi(对于 MySQL):
    从 PHP 8.2+ 开始我们可以利用execute_query()它用一种方法准备、绑定参数并执行 SQL 语句:

    $result = $db->execute_query('SELECT * FROM employees WHERE name = ?', [$name]);
     while ($row = $result->fetch_assoc()) {
         // Do something with $row
     }
    

    最高可达 PHP8.1:

     $stmt = $db->prepare('SELECT * FROM employees WHERE name = ?');
     $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
     $stmt->execute();
     $result = $stmt->get_result();
     while ($row = $result->fetch_assoc()) {
         // Do something with $row
     }
    

如果您要连接到 MySQL 以外的数据库,则可以参考特定于驱动程序的第二个选项(例如,pg_prepare() and pg_execute()对于 PostgreSQL)。 PDO 是通用选项。


正确设置连接

PDO

使用时请注意PDO访问 MySQL 数据库real准备好的陈述是默认不使用。要解决此问题,您必须禁用准备语句的模拟。使用创建连接的示例PDO is:

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

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

在上面的例子中,错误模式并不是绝对必要的,但建议添加。这样,PDO 将通过抛出以下错误来通知您所有 MySQL 错误:PDOException.

What is 强制的,然而,是第一个setAttribute()行,告诉 PDO 禁用模拟准备好的语句并使用real准备好的陈述。这可以确保语句和值在发送到 MySQL 服务器之前不会被 PHP 解析(让可能的攻击者没有机会注入恶意 SQL)。

虽然您可以设置charset在构造函数的选项中,需要注意的是“旧”版本的 PHP(5.3.6 之前)默默地忽略了 charset 参数在 DSN 中。

Mysqli

对于 mysqli,我们必须遵循相同的例程:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // error reporting
$dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test');
$dbConnection->set_charset('utf8mb4'); // charset

解释

您传递给的 SQL 语句prepare由数据库服务器解析和编译。通过指定参数(或者?或命名参数,例如:name在上面的示例中)您告诉数据库引擎您要过滤的位置。然后当你打电话时execute,准备好的语句与您指定的参数值相结合。

这里重要的是参数值与编译后的语句结合在一起,而不是 SQL 字符串。 SQL 注入的工作原理是在脚本创建要发送到数据库的 SQL 时欺骗脚本包含恶意字符串。因此,通过将实际的 SQL 与参数分开发送,您可以限制最终出现意外结果的风险。

使用准备好的语句时发送的任何参数都将被视为字符串(尽管数据库引擎可能会进行一些优化,因此参数当然也可能最终为数字)。在上面的例子中,如果$name变量包含'Sarah'; DELETE FROM employees结果只是搜索字符串"'Sarah'; DELETE FROM employees",你最终不会得到一张空桌子.

使用准备好的语句的另一个好处是,如果您在同一个会话中多次执行相同的语句,它只会被解析和编译一次,从而提高速度。

哦,既然您询问了如何进行插入,这里有一个示例(使用 PDO):

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

$preparedStatement->execute([ 'column' => $unsafeValue ]);

准备好的语句可以用于动态查询吗?

虽然您仍然可以对查询参数使用准备好的语句,但动态查询本身的结构无法参数化,并且某些查询功能也无法参数化。

对于这些特定场景,最好的办法是使用白名单过滤器来限制可能的值。

// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何防止 PHP 中的 SQL 注入? 的相关文章

  • Blade @if 中的 Laravel 会话变量

    当我尝试使用 Laravel Session 在刀片中设置 JS 变量来刷新一些数据时 我在 Laravel 4 2 中遇到了一些奇怪的情况 这很简单 我不知道我错过了什么 目标 在用户注册后立即触发 Javascript 网站浏览 方法
  • postgres 有 CLOSEST 运算符吗?

    我正在寻找这样的东西 给定一个表格 id number 1 7 2 1 25 3 1 01 4 3 0 查询SELECT FROM my table WHEREnumberCLOSEST 1 将返回第 3 行 我只关心数字 现在我有一个程序
  • 当“修复表”查询在 mysql 中不起作用时该怎么办?

    我收到此错误 表的存储引擎不支持修复 当我尝试使用查询修复表时repair table tbl college master 表是 innodb 类型 但我不知道我收到此错误 See 手册 http dev mysql com doc re
  • 从 XML 节点 PHP DOM 中删除所有子节点

    我想使用 PHP DOM 从 XML 节点中删除所有子节点 以下之间有什么区别 A while parentNode gt hasChildNodes parentNode gt removeChild parentNode gt chil
  • Magento - 当我的订单取消或退款时如何运行代码

    如果订单被取消或退款 我的支付模块需要向支付服务发送通知 我假设订单页面 在管理后端 上的 取消 按钮将取消订单 而 贷项通知单 按钮 创建发票后 将退还订单 如何针对这些事件运行我的代码 我尝试在付款方式模型中使用 cancel 方法 但
  • 对于数据库来说,选择正确的数据类型会影响性能吗?

    如果是这样 为什么 我的意思是 tinyint 的搜索速度比 int 快吗 如果是这样 性能上的实际差异是什么 是的 根据数据类型 它确实有所不同 int vs tinyint不会在速度上产生明显的差异 但会在数据大小上产生差异 假设tin
  • 如何在 apache 上为锚点 cms 重写指令

    我使用的是一个名为anchor的cms http anchorcms com docs getting started configuration http anchorcms com docs getting started config
  • MySql 最后插入 ID,连接器 .net

    我正在使用 MySql Connector net 我需要获取最后一个查询生成的插入 id 现在 我假设返回值是MySqlHelper ExecuteNonQuery应该是最后一个插入id 但它只返回1 我正在使用的代码是 int inse
  • 使用 PHP 获取 2 个同名 HTML 输入标签的值

    假设我有下表
  • Symfony2 Twig 扩展

    我在实现树枝扩展时遇到一些问题 我需要创建自己的过滤器 子过滤器 所以我想到了使用twig扩展 我在 MyApp Bundle WebsiteBundle 和文件上创建了一个名为 Extension 的文件夹 网站扩展 php namesp
  • 显示表中的记录

    我的第一个 PHP 项目遇到了一些麻烦 我试图从 MySQL 数据库 有 3 条记录 获取数据并将其显示在表格中 问题是它似乎只显示记录 2 和 3 它跳过了第 1 条记录 请参阅我的代码并在下面显示 if mysqli connect e
  • 运行没有扩展名的 PHP 页面

    我想在 apache Web 服务器上运行我的 PHP 网页 而不需要 php扩大 所以我添加了以下代码 RewriteEngine on RewriteBase Rewritecond REQUEST URI NC RewriteRule
  • 如何在SSRS中的表上创建热图?

    如何在 SSRS 中创建这样的内容 颜色将根据行中的值 承销商 从红色变为绿色 所有这些都在一个组中 您可以通过右键单击各个单元格并根据表达式设置填充颜色来完成此操作 In the Image below I ve mistakingly
  • Python:如何使用生成器来避免 sql 内存问题

    我有以下方法来访问 mysql 数据库 并且查询在服务器中执行 我无权更改有关增加内存的任何内容 我对生成器很陌生 并开始阅读更多有关它的内容 并认为我可以将其转换为使用生成器 def getUNames self globalUserQu
  • 为什么我不能在 TCPDF 表中使用 č,ć,đ 图表?

    我正在为我的网站构建一个 tcpdf 文件 该 tcpdf 文件中有一个包含一些数据的表格 但我无法使该章程正常工作 对于编码 我使用 windows 1250 宪章女巫不起作用 我已经尝试过 utf 8 但仍然没有得到这个章程 tcpdf
  • SQL参数化查询不显示结果

    我的 DataAcess 类中有以下函数 但它没有显示任何结果 我的代码如下 public List
  • 将 SQL 数据中的一行映射到 Java 对象

    我有一个 Java 类 其实例字段 以及匹配的 setter 方法 与 SQL 数据库表的列名相匹配 我想优雅地从表中获取一行 到 ResultSet 中 并将其映射到此类的实例 例如 我有一个 Student 类 其中包含实例字段 FNA
  • WooCommerce 使用 AJAX 设置购物车数量?

    我已经为此绞尽脑汁好几天了 需要一些指导 我正在为 WooCommerce 网站完全从头开始制作自定义主题 现在我正在尝试让购物车功能正常工作 我一直试图使用按钮 来更新购物车中产品的数量 对我来说问题似乎是WC 我在functions p
  • 通过 __get() 通过引用返回 null

    快速规格 PHP 5 3 error reporting 1 the highest 我正在使用 get 通过引用技巧神奇地访问对象中任意深度的数组元素 快速示例 public function get key return isset t
  • SQLite HAVING 比较错误

    我有一个测试 SQLite 表 用于存储带有值的报告数据 CREATE TABLE IF NOT EXISTS test fact daily revenue date TEXT revenue NUMERIC product TEXT I

随机推荐

  • 初始化谷歌地图时,mapFragment.getMapAsync(this)处出现空指针异常

    当我使用 Google Play Services v6 5 87 时 调用时出现空指针异常getMapAsync 我正在使用一个SupportMapFragment in my Fragment的 xml 布局 My code Suppo
  • Clojure 理解示例

    我在用docjure它的选择列功能需要一个列映射 我想获取所有列 而无需手动指定 如何生成以下惰性无限向量序列 A B C D E AA AB AC ZZ XFD 你的问题归结为 如何将数字转换为包含字母 A Z 的 26 进制字符串 这是
  • 使用OpenGL替代Canvas - Android

    我正在尝试用更快的 opengl es 表面替换我已经拥有的基于 Canvas 的渲染系统 但是 我似乎无法让 openGL 渲染器以充当 2d 场的方式符合 而不是透视图 我当前的渲染器代码如下所示 Override public voi
  • 是否可以复制某个控件的所有属性? (C# 窗口窗体)

    例如 我有一个DataGridView用蓝色控制BackgroundColor属性等 有没有一种方法可以以编程方式将这些属性转移或传递给另一个属性DataGridView控制 像这样的东西 dtGrid2 Property dtGrid1
  • \G 在 .split 中如何工作?

    我喜欢用 Java 进行代码高尔夫 尽管 Java 过于冗长而缺乏竞争力 即用尽可能少的字节完成某个挑战 在我的一个答案中 我有以下代码 for var p A4 B8 CU EM EW E3 G6 G9 I1 L7 NZ O0 R2 S5
  • 更新游标的记录,其中表名是参数

    我正在调整一些 PL pgSQL 代码 以便我的refcursor可以将表名作为参数 因此我更改了以下行 declare pointCurs CURSOR FOR SELECT from tableName for update 与这个 O
  • Hibernate多对多关联:左侧集合包含元素,但右侧集合为空

    我在持久层中遇到了多对多关联的问题 我的场景如下 一个用户可以拥有多个角色 一个角色可以附加多个用户 在测试过程中我遇到了一个奇怪的行为 我创建了角色对象和几个用户对象 该角色已设置给每个用户 此后 使用 DAO 保存用户 然后 在保存用户
  • 使用 SMTP 身份验证时通过 PEAR 发送 HTML 消息会返回错误

    我正在尝试在 PHP 中使用 SMTP 身份验证向 Gmail 发送 HTML 消息 这是我正在使用的脚本 require once Mail php require once Mail mime php from Some Name lt
  • 数据库未从资产文件夹复制到设备

    我的目录中有一个 db 文件assets文件夹 我已将其复制到data data
  • MPAndroidChart PieChart如何设置标签文本?

    得到以下代码 Legend legend mChart getLegend legend setLabels new String aaaaa bbbbb ccccc 此设置不生效 还有其他方法设置文本吗 我在 v3 0 0 中找不到方法
  • 委托/函数转换和误导性编译器错误消息

    我认为 F 函数和 System Func 之间的转换必须手动完成 但似乎存在编译器 有时 为您完成的情况 当出现错误时 错误消息不准确 module Foo let dict new System Collections Generic
  • 如何计算 MkMapview 中两点之间的距离?

    在 iPhone 应用程序中 如何计算两点之间的距离MKMapView如下图所示 第一个点将是地图视图中可见地图的中心点 第二个点将是地图视图的可见矩形的任何角 例如 这里我采用了左上角的点 我想以米为单位计算这个距离 我怎样才能做到这一点
  • 有权访问会话状态的 Global.asax 事件

    我正在尝试访问 global asax 中每个请求 页面 文档 PDF 等 的会话状态 我知道我不能在 Application BeginRequest 中执行此操作 并且我认为我可以在 Application AcquireRequest
  • SimpleForm 默认输入类

    我正在使用 SimpleForm Bootstrap 如何为所有属性添加属性type text 输入类 span12 输出类似这样的东西 div class controls div
  • 发送 HEAD 请求时 cURL 挂起 15 秒

    背景 我一直在使用 CLI 通过 CLI 对一些 HTTP 请求进行计时time和工具 例如wget and curl如下 usr bin time v wget spider http localhost index usr bin ti
  • Javascript 中带有负移位计数的左移

    我在 Javascript 中注意到的一件事 一个 Returns 0 when a even Returns 2147483648 when a odd 同样 当 1更改为其他一些 ve数字 有人可以解释一下幕后发生了什么位操作吗 或者行
  • Keras 中随时间变化的最大池化

    我正在使用 CNNKeras对于 NLP 任务 我尝试实现随时间推移的最大池化 而不是最大池化 关于如何实现这一目标有什么想法 技巧吗 我所说的最大随时间池化的意思是池化最高值 无论它们位于向量中的哪个位置 假设您的数据形状是 batch
  • 如何管理多个环境的 ASP.NET Core bundleconfig.json?

    使用 ASP NET Core 的最佳实践是什么bundleconfig json开发环境与生产环境 先前的捆绑器 捆绑集合 会注意 DEBUG 编译器指令 并且在调试时不会缩小脚本列表 看起来新的范式似乎是
  • Hg (Mercurial):有什么办法可以“留出”工作副本供以后使用吗?

    场景 在上次提交之后 您决定对代码库进行一些广泛的重构 一段时间后 您意识到花费的时间比预期的要长 您真的宁愿将重构推迟到另一时间 并致力于更紧迫的任务 但您不想丢失迄今为止所做的所有重构工作 那么 有没有办法 归档 或 分支 工作副本 本
  • 如何防止 PHP 中的 SQL 注入?

    这个问题的答案是社区努力 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 如果用户输入未经修改就插入到 SQL 查询中 则应用程序很容易受到攻击SQL注入 如以下示例所示 unsafe variable POST user input