个性化阅读
专注于IT技术分析

什么是SQL注入以及如何在PHP应用程序中进行预防?

本文概述

因此, 你认为你的SQL数据库是高性能的, 并且可以立即销毁吗?好吧, SQL注入不同意!

是的, 我们正在谈论的是立即销毁, 因为我不想以”加强安全性”和”防止恶意访问”这一la脚的常用术语来打开本文。 SQL注入是本书中的一个古老技巧, 每个人(每个开发人员)都非常了解它, 并且非常了解如何防止它。除了它们滑倒的那一个奇怪的时间, 结果可能是灾难性的。

如果你已经知道什么是SQL Injection, 请随时跳到本文的后半部分。但是对于那些刚进入Web开发领域并梦想担任更高级职位的人, 有必要进行一些介绍。

什么是SQL注入?

理解SQL注入的关键在于它的名称:SQL + Injection。这里的”注射”一词没有任何医学含义, 而是动词”注射”的用法。这两个词在一起传达了将SQL放入Web应用程序的想法。

将SQL放入Web应用程序中。 。 。嗯。 。 。那不是我们在做什么吗?是的, 但是我们不希望攻击者来驱动我们的数据库。让我们借助示例来了解这一点。

假设你要为本地电子商务商店构建一个典型的PHP网站, 因此你决定添加如下联系表格:

<form action="record_message.php" method="POST">
  <label>Your name</label>
  <input type="text" name="name">
  
  <label>Your message</label>
  <textarea name="message" rows="5"></textarea>
  
  <input type="submit" value="Send">
</form>

并假设文件send_message.php将所有内容存储在数据库中, 以便商店所有者以后可以读取用户消息。它可能有一些这样的代码:

<?php

$name = $_POST['name'];
$message = $_POST['message'];

// check if this user already has a message
mysqli_query($conn, "SELECT * from messages where name = $name");

// Other code here

因此, 你首先尝试查看该用户是否已经有未读邮件。查询SELECT * from name = $ name的消息看起来很简单, 对吧?

错误!

我们天真地打开了立即销毁数据库的大门。为此, 攻击者必须满足以下条件:

  • 该应用程序在SQL数据库上运行(今天, 几乎每个应用程序都在运行)
  • 当前数据库连接对数据库具有”编辑”和”删除”权限
  • 重要表的名称可以猜测

第三点意味着, 既然攻击者知道你正在经营一家电子商务商店, 那么很有可能将订单数据存储在订单表中。有了所有这些, 攻击者所需要做的就是提供以下名称:

什么是SQL注入以及如何在PHP应用程序中进行预防?2

乔截断订单;?是的先生!让我们看看由PHP脚本执行查询时查询将变成什么:

SELECT * FROM message where where name = Joe;截断订单;

好的, 查询的第一部分有语法错误(” Joe”周围没有引号), 但是分号强制MySQL引擎开始解释新的:截断订单。如此一来, 整个订单历史就消失了!

现在你已经了解了SQL Injection的工作原理, 现在该看看如何停止它。成功进行SQL注入需要满足的两个条件是:

  1. PHP脚本应具有对数据库的修改/删除特权。我认为这对所有应用程序都是如此, 并且你将无法将应用程序设置为只读。 ????猜猜是什么, 即使我们删除了所有修改权限, SQL注入仍然可以允许某人运行SELECT查询并查看所有数据库, 包括敏感数据。换句话说, 降低数据库访问级别不起作用, 并且你的应用程序仍然需要它。
  2. 用户输入正在处理中。 SQL注入可以起作用的唯一方法是当你接受用户的数据时。同样, 仅因为担心SQL注入而停止应用程序的所有输入是不切实际的。

防止PHP中的SQL注入

现在, 鉴于数据库连接, 查询和用户输入已成为生活的一部分, 我们如何防止SQL注入?幸运的是, 它非常简单, 有两种方法可以做到:1)清理用户输入, 以及2)使用准备好的语句。

清理用户输入

如果你使用的是较旧的PHP版本(5.5或更低版本, 并且在共享主机上经常发生这种情况), 明智的做法是通过mysql_real_escape_string()函数运行所有用户输入。基本上, 它会删除字符串中的所有特殊字符, 以使它们在被数据库使用时失去其含义。

例如, 如果你有一个像我一样的字符串, 则攻击者可以使用单引号(‘)来操纵正在创建的数据库查询并导致SQL注入。通过mysql_real_escape_string()运行它会产生一个字符串, 在单引号中添加一个反斜杠, 以使其转义。结果, 整个字符串现在作为无害的字符串传递到数据库, 而不是能够参与查询操作。

这种方法有一个缺点:这是一种非常古老的技术, 与PHP中较旧的数据库访问形式一起出现。从PHP 7开始, 此功能甚至不再存在, 这使我们进入了下一个解决方案。

使用准备好的陈述

预备语句是一种使数据库查询更安全可靠的方法。我们的想法是, 我们首先将要发送的查询的结构告诉数据库, 而不是将原始查询发送到数据库。这就是我们”准备”声明的意思。准备好语句后, 我们会将信息作为参数化的输入传递, 以便数据库可以通过将输入插入我们之前发送的查询结构中来”填补空白”。这消除了输入可能具有的任何特殊功能, 从而在整个过程中将它们视为纯变量(或有效载荷, 如果需要)。准备好的语句如下所示:

<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}

// prepare and bind
$stmt = $conn->prepare("INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $firstname, $lastname, $email);

// set parameters and execute
$firstname = "John";
$lastname = "Doe";
$email = "[email protected]";
$stmt->execute();

$firstname = "Mary";
$lastname = "Moe";
$email = "[email protected]";
$stmt->execute();

$firstname = "Julie";
$lastname = "Dooley";
$email = "[email protected]";
$stmt->execute();

echo "New records created successfully";

$stmt->close();
$conn->close();
?>

我知道, 如果你不熟悉准备好的声明, 则过程听起来不必要地复杂, 但是这一概念值得你付出努力。这是一个很好的介绍。

对于那些已经熟悉PHP的PDO扩展并使用它来创建准备好的语句的人, 我有一点建议。

警告:设置PDO时要小心

使用PDO进行数据库访问时, 我们可能会陷入一种错误的安全感。 “嗯, 我正在使用PDO。现在, 我无需考虑其他任何事情”, 这就是我们通常的思维方式。的确, PDO(或MySQLi预准备的语句)足以阻止各种SQL注入攻击, 但是在设置它时必须小心。仅复制教程或先前项目中的代码并继续前进是很常见的, 但是此设置可以撤消所有操作:

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

该设置的作用是告诉PDO模拟预备语句, 而不是实际使用数据库的预备语句功能。因此, PHP会将简单的查询字符串发送到数据库, 即使你的代码看起来像是在创建准备好的语句并设置参数。换句话说, 你像以前一样容易受到SQL注入的攻击。 ????

解决方案很简单:确保将此仿真设置为false。

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

现在, PHP脚本被迫在数据库级别使用准备好的语句, 从而防止了各种SQL注入。

防止使用WAF

你是否知道还可以使用WAF(Web应用程序防火墙)保护Web应用程序免受SQL注入?

好吧, 不仅是SQL注入, 而且还有许多其他的第7层漏洞, 例如跨站点脚本, 破坏的身份验证, 跨站点伪造, 数据泄露等。你可以使用自托管(如Mod Security)或基于云的漏洞, 如下所述。

  • JUICE
  • 云耀斑
  • Indusface

SQL注入和现代PHP框架

SQL注入是如此普遍, 如此简单, 如此令人沮丧和如此危险, 以至于所有现代PHP Web框架都内置了对策。例如, 在WordPress中, 我们具有$ wpdb-> prepare()函数, 而如果你使用的是MVC框架, 它将为你完成所有肮脏的工作, 并且你甚至不必考虑防止SQL注入。有点烦人的是, 在WordPress中你必须显式地准备语句, 但是, 嘿, 我们正在谈论的是WordPress。 ????

无论如何, 我的观点是, 现代的Web开发人员不必考虑SQL注入, 因此, 他们甚至不知道这种可能性。因此, 即使他们在应用程序中打开一个后门程序(可能是$ _GET查询参数, 也有旧习惯触发脏查询), 结果可能是灾难性的。因此, 最好花一些时间深入了解基础。

总结

SQL注入是对Web应用程序的非常讨厌的攻击, 但是很容易避免。正如我们在本文中看到的, 在处理用户输入时(请注意, SQL注入并不是处理用户输入带来的唯一威胁)并且查询数据库就足够了。就是说, 我们并非总是在Web框架的安全性下工作, 因此最好知道这种攻击而不是落伍。

赞(0)
未经允许不得转载:srcmini » 什么是SQL注入以及如何在PHP应用程序中进行预防?

评论 抢沙发

评论前必须登录!