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

本文概述

  • 什么是SQL注入?
  • 防止PHP中的SQL注入
  • 防止使用WAF
  • SQL注入和现代PHP框架
因此, 你认为你的SQL数据库是高性能的, 并且可以立即销毁吗?好吧, SQL注入不同意!
是的, 我们正在谈论的是立即销毁, 因为我不想以” 加强安全性” 和” 防止恶意访问” 这一la脚的常用术语来打开本文。 SQL注入是本书中的一个古老技巧, 每个人(每个开发人员)都非常了解它, 并且非常了解如何防止它。除了它们滑倒的那一个奇怪的时间, 结果可能是灾难性的。
【什么是SQL注入以及如何在PHP应用程序中进行预防()】如果你已经知道什么是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="http://www.srcmini.com/Send"> < /form>

并假设文件send_message.php将所有内容存储在数据库中, 以便商店所有者以后可以读取用户消息。它可能有一些这样的代码:
< ?php$name = $_POST['name']; $message = $_POST['message']; // check if this user already has a messagemysqli_query($conn, "SELECT * from messages where name = $name"); // Other code here

因此, 你首先尝试查看该用户是否已经有未读邮件。查询SELECT * from name = $ name的消息看起来很简单, 对吧?
错误!
我们天真地打开了立即销毁数据库的大门。为此, 攻击者必须满足以下条件:
  • 该应用程序在SQL数据库上运行(今天, 几乎每个应用程序都在运行)
  • 当前数据库连接对数据库具有” 编辑” 和” 删除” 权限
  • 重要表的名称可以猜测
第三点意味着, 既然攻击者知道你正在经营一家电子商务商店, 那么很有可能将订单数据存储在订单表中。有了所有这些, 攻击者所需要做的就是提供以下名称:
什么是SQL注入以及如何在PHP应用程序中进行预防()

文章图片
乔截断订单;?是的先生!让我们看看由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 connectionif ($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框架的安全性下工作, 因此最好知道这种攻击而不是落伍。

    推荐阅读