php - SQL - SQL 注入的真正危险是什么?
问题描述
注意:这不是关于什么是 SQL Injection的问题,而是一个澄清实际漏洞的问题,特别是考虑到一些特定的测试用例。
背景:请看这个名为Modern Rouge的小组的视频。或者,您可以忽略它,因为对于没有技术技能并且还不熟悉SQL 注入的人来说,它有点过于简单化了。我会在需要时指出我们的重要部分。
所以,对于那些不知道什么是 SQL 注入的人(我只是为了完整性和为我的特定问题提供背景而添加它),假设我有这样的 PHP 代码:
$query = "SELECT * FROM users WHERE username='$username'";
此代码易受攻击,因为假设恶意最终用户将其用户名输入为' or 1=1;--
,这可能会进行最终查询
SELECT * FROM users WHERE username='' or 1=1;--'
这没有预期的效果。
所以,现在在 4:00左右观看视频。
他们在测试网站上给出的 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--
然而,这也让我感到困惑。除非我将这些数据放入一个漂亮的表或其他东西中,否则数据不会永远离开后端,即使查询很容易受到攻击?除非我不经意间将其提供给他们,否则他们怎么可能得到这些信息?
这就引出了一个更大的问题:SQL 注入的危险是什么?它是纯粹的理论,还是存在攻击者可以通过纯 SQL 注入执行登录或访问数据库中的所有表等操作的真实案例?
编辑:从头开始。让我缩小一点。
它如何离开后端?即使某些东西查询了错误的东西,我的攻击者如何得到它?像 PDO 和 SQLI 这样的 DB API 将信息返回给 PHP,而不是结果页面。一个编写良好的 PHP 脚本不应该捕捉到错误的数据,或者至少不应该将其全部回显给用户吗?
解决方案
SQL 注入不是理论上的。几乎每个月都有关于使用 SQL 注入进行的实际数据泄露的新闻报道。有一个很棒的网站可以收集它们:https ://codecurmudgeon.com/wp/sql-injection-hall-of-sham/
这是上个月的一个好消息:
https://motherboard.vice.com/en_us/article/vba5nb/fornite-login-hack-epic-games-website
Epic Games 网站上的漏洞允许黑客登录任何“堡垒之夜”玩家的账户
...
据 Check Point 研究人员称,该页面现在已离线,其中包含两个经常在网站中发现的漏洞:SQL 注入(或 SQLi)和跨站点脚本(或 XSS)。
关于您提供的示例,我建议您在应用程序代码中验证密码。然后您可以区分“未找到帐户”与“找到帐户,但密码错误”(您不想向用户透露这一点,但您可能希望记录错误,并可能锁定帐户,如果他们密码尝试失败次数过多)。
但无论如何,SQL 语句容易受到 SQL 注入的攻击。不仅使用您展示的“OR 1=1”技巧,而且如果您可以诱使查询运行基于 UNION 的 SQL 查询:
$query = "SELECT * FROM users WHERE username='' UNION ALL SELECT * FROM INFORMATION_SCHEMA.TABLES -- '";
^^ $username ...
如果攻击者可以在您的应用程序中找到 SQL 查询(不一定是按帐户名搜索),他们可以使用此技术查询您的所有表。然后他们可以进一步使用 UNION 技术来查询所有表中的数据,一旦他们知道他们的名字。
关于您的后续问题:
“数据如何离开后端?”
考虑一下您的密码检查代码(对于上面的查询)是否如下所示:
$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
then 这就是查询将返回的值。他们觉得使用$row['username']
起来很安全。
但它不是——它是来自 UNION 另一部分的一些数据。通过使用 CONCAT() 和 GROUP_CONCAT(),攻击者甚至可以将多行的多列放在一起。他们做到了。他们可能需要多次尝试才能让他们的攻击查询在正确的位置有正确数量的列,但他们显然没有更好的事情可做。
推荐阅读
- javascript - 在对象数组中的某个属性中查找所有具有最大值的对象,并从同一对象返回其他属性的值
- xamarin.forms - UWP - 无法解析程序集或 Windows 元数据文件
- google-sheets - 查找总和或任何有效的方法
- rest - 为 yii2 运行 codecept REST 如何获取 $_SERVER['PHP_AUTH_USER']?
- flutter - 如何通过 TapGestureRecognizer 获取 TextSpan 的信息
- c# - 以编程方式调用 ASMX 中的所有操作
- node.js - 无法在 Ubuntu 终端中运行 NPM 或 ng build 或 Apache
- javascript - TypeScript - 自定义类元素的 Array.map
- elasticsearch - 使用 JMeter 向 Elasticsearch 进行身份验证
- c# - ADAL AcquireTokenAsync 不想要父窗口