SQL 注入

SQL 注入是一种通过表单输入字段或 URL 查询参数执行 SQL 命令的技术。这会导致未经授权地访问数据库(一种黑客攻击类型)。

如果 SQL 注入成功,未经授权的人员可能会从数据库表中读取、创建、更新甚至删除记录。这种技术主要被黑客、渗透测试人员、质量保证人员和安全研究人员使用(但不限于)。


使用多语句的 SQL 注入

假设我们的网站上有一个搜索表单,用于按产品 ID 搜索产品。搜索产品的 PHP 代码片段可能如下所示:

$prod_id = $_GET["prod_id"];

$sql = "SELECT * FROM Products WHERE product_id = " . $prod_id;

如果用户在表单中输入 20; DROP TABLE Products;,那么 SQL 语句将变为:

SELECT * FROM Products WHERE product_id = 20; DROP TABLE Products;

现在,这条 SQL 语句会从数据库中删除 Products 表。这之所以可能,是因为大多数数据库系统可以同时执行多条语句。

How SQL is injected in an app?
示例:SQL 注入

使用“永远为真”条件的 SQL 注入

执行 SQL 注入的另一种方法是传递一个始终导致 TRUE 的条件,这样无论如何都会获取数据。

让我们看一下另一个 PHP 代码片段,我们的网站上有一个登录表单,需要通过提供凭据来获取用户。

$username = $_POST["username"];
$password = $_POST["password"];

$sql = "SELECT * FROM Users WHERE username = \"" . $username . "\" AND password = \"" . $password . "\"";

如果用户将用户名输入为 invalid_user" OR "1"="1,将密码输入为 invalid_pass" OR "1"="1,那么 SQL 语句将变为

SELECT * FROM Users WHERE username = "invalid_user" OR "1"="1" AND password = "invalid_pass" OR "1"="1"

由于 "1"="1" 始终为 TRUE,无论用户输入什么 usernamepassword,SQL 都会从数据库中获取所有用户的数据。


如何保护 SQL 语句免受注入?

验证用户输入

在实际将用户输入数据发送到数据库之前,我们应该始终对其进行验证。一些最佳实践包括:去除空格、解析特殊字符、限制输入大小等。

例如,

$data = $_POST["name"];

$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);

此处,此 PHP 代码片段在一定程度上验证了输入数据。


使用 ORM

ORM(对象关系映射)是一个基本上将 SQL 语句解析为编程语言代码,反之亦然的工具。

如果我们使用 ORM,大部分情况下我们不必编写原始 SQL。由于 ORM 是根据良好实践和安全协议设计的,因此它们安全且易于使用。

例如,考虑下面的 SQL 代码

SELECT * FROM Users WHERE id = 5;

其在 Python 的 SQLAlchemy ORM 中的等效代码将是

select(Users).where(Users.id == 5)

使用预处理语句

保护 SQL 语句免受注入的另一种方法是使用预处理语句。

预处理语句基本上是带占位符的 SQL 语句。传递的参数只是替换占位符的位置。

例如,

$sql = "INSERT INTO Users (first_name, last_name, email) VALUES (?, ?, ?)";

mysqli_stmt_bind_param($sql, "sss", $first_name, $last_name, $email);

$first_name = "Harry";
$last_name = "Potter";
$email = "[email protected]";

mysqli_stmt_execute($stmt);

在这里,值只放置在 ? 占位符的位置,并且 SQL 语句的结构得以保留。


使用框架

此外,如果我们要构建一个实际世界的应用程序,最好始终使用框架(如 Django、Laravel、ASP.net 等),而不是从头开始编写代码。

这是因为这些框架默认处理 SQL 注入和许多其他常见问题。


结论

SQL 注入是攻击任何 Web 应用程序的一种非常常见的方式。

因此,如果我们在构建应用程序时使用原始 SQL 语句,我们必须彻底测试和验证它们。

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战