SQL - SQL注射的真正危险是什么?

SQL - What is the real danger of SQL injection?

NOTE: This is not a question about what is SQL Injection, but rather a question to clear up what the actual vulnerability, particularly given some specific test cases.

Background: Please see this video by a group called Modern Rouge. Or, you can ignore it, as it's kind of oversimplified for people who don't have technical skills and aren't already familiar with SQL Injection. I will point our the important part when it's needed.

所以,对于那些不知道什么是 SQL 注入的人(我只是为了完整性而添加这个,并为我的特定问题提供背景),假设我有 PHP代码如下:

$query = "SELECT * FROM users WHERE username='$username'";

此代码容易受到攻击,因为假设恶意最终用户将其用户名输入为 ' or 1=1;--,这可能会导致最终查询

SELECT * FROM users WHERE username='' or 1=1;--'

没有达到预期的效果。

所以,现在观看 the 4:00 mark 左右的视频。

他们在测试网站上给出的 SQL 注入示例,他们使用 SQL 注入来绕过密码检查。

这是我不明白的,在现实生活中,我不会检查 PHP 中的密码,使这个特定示例变得无用吗?例如:

if($userRecordFromDB["pwd"] == $pwd) { // User authenticated.

SQL 注入无法绕过我的 PHP 身份验证,我说得对吗?这里的漏洞是什么?除非我将密码检查与我的查询相关联(我承认本示例可以这样做),否则即使我有易受攻击的查询,我的网站也不应该易受攻击。

第二个相关问题:视频继续暗示单个漏洞可能允许攻击者访问我的整个数据库!我假设他们的意思是攻击者可以做这样的事情:

SELECT * FROM users WHERE username='' or 1=1; SELECT * FROM creditInformationTable where 1=1--'

$username 当然是 ' or 1=1; SELECT * FROM creditInformationTable where 1=1--

然而,这也让我感到困惑。除非我将这些数据放入一个很好的 table 或其他东西中,否则数据不会永远不会离开后端,即使查询是易受攻击的吗?除非我不小心给了他们这些信息,否则他们怎么可能得到这些信息?

这让我想到了一个更大的问题:SQL 注射有什么危险?这纯粹是理论上的,还是存在攻击者可以通过纯 SQL 注入进行登录或访问数据库中的所有 table 之类的真实案例?

编辑: 从头开始​​。让我缩小一点。

它如何离开后端?即使某些东西查询了错误的东西,我的攻击者怎么会得到它?像 PDO 这样的数据库 API 和 SQLI return 信息到 PHP,NOT 结果页面。一个写得很好的 PHP 脚本难道不应该捕捉到那里的错误数据,或者至少不应该将它全部回显给用户吗?

SQL注入不是理论上的。几乎每个月都有关于使用 SQL 注入进行真实数据泄露的新闻报道。有一个收集它们的好网站:https://codecurmudgeon.com/wp/sql-injection-hall-of-shame/

这是上个月的一个好作品:

https://motherboard.vice.com/en_us/article/vba5nb/fornite-login-hack-epic-games-website

Bugs on Epic Games Site Allowed Hackers to Login to Any ‘Fortnite’ Player’s Account

...

That page, which is now offline, contained two vulnerabilities that are often found in websites: an SQL Injection (or SQLi), and a Cross-Site Scripting (or XSS), according to Check Point researchers.

关于您提供的示例,我确实建议在应用程序代码中验证密码。然后你可以区分 "no account found" 和 "account found, but password was wrong"(你不想向用户透露这个,但你可能想记录错误,如果他们有太多失败,可能会锁定帐户密码尝试)。

但无论如何,SQL 语句容易受到 SQL 注入攻击。不仅使用您展示的 "OR 1=1" 技巧,而且如果您可以将查询欺骗为基于 运行 UNION 的 SQL 查询:

$query = "SELECT * FROM users WHERE username='' UNION ALL SELECT * FROM INFORMATION_SCHEMA.TABLES -- '";
                                              ^^ $username ...

如果攻击者可以在您的应用程序中找到 SQL 查询(不一定是按帐户名搜索),他们可以使用此技术来查询您的所有表。然后他们可以进一步使用 UNION 技术来查询所有表中的数据,一旦他们知道他们的名字。


关于您的后续问题:

"How does the data leave the back-end?"

考虑一下您的密码检查代码(针对上述查询)是否如下所示:

$query = "SELECT id, username, password_hashed FROM users WHERE username='$username'";

$stmt = $pdo->query($query);
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
  if (!password_verify($password, $row['password_hashed'])) {
    die("Invalid login for user {$row['username']}");
  }
}

看到了吗? SQL 查询的结果输出给用户。对于此代码的开发人员来说,很明显,因为他们只是查询了 $username 那么这就是查询将返回的值。他们觉得 $row['username'] 使用安全。

但它不是 — 它是来自 UNION 另一部分的一些数据。通过使用 CONCAT() 和 GROUP_CONCAT(),攻击者甚至可以将多行的多列放在一起。 他们确实这样做了。他们可能需要多次尝试才能让他们的攻击查询在正确的位置有正确数量的列,但他们显然没有更好的事情可做。