1前言
SQL注入,一般通过输入或参数提交,通过SQL语句,攻击数据库,会造成严重的安全隐患。SQL注入是网络攻击中比较常见的方式之一,它不是利用操作系统的bug来实现攻击,而是攻击程序员的疏忽或漏洞。
2什么是SQL注入?
SQL注入是一个 Web 安全漏洞,允许攻击者干扰应用程序对其数据库进行的查询。它通常允许攻击者查看他们通常无法检索的数据。这可能包括属于其他用户的数据,或应用程序本身能够访问的任何其他数据。在许多情况下,攻击者可以修改或删除此数据,从而导致应用程序的内容或行为持续更改。
在某些情况下,攻击者可以升级 SQL 注入攻击以破坏基础服务器或其他后端基础结构,或者执行拒绝服务攻击。
成功的 SQL 注入攻击可导致对敏感数据(如密码、信用卡详细信息或个人用户信息)的未经授权的访问。近年来,许多备受瞩目的数据泄露事件都是SQL注入攻击的结果,导致声誉受损和监管罚款。在某些情况下,攻击者可以获得进入组织系统的持久后门,从而导致长期危害,并可能在很长一段时间内被忽视。
SQL注入攻击的危害性
-
SQL 注入攻击允许攻击者欺骗身份、篡改现有数据、导致拒绝问题(如取消事务或更改余额)、允许完全泄露系统上的所有数据、销毁数据或使其不可用,并成为数据库服务器的管理员。
-
SQL注入在PHP和ASP应用程序中非常普遍,因为较旧的功能接口很普遍。由于可用的编程接口的性质,J2EE 和 ASP.NET 应用程序不太可能轻易利用 SQL 注入。
-
SQL注入攻击的严重程度受到攻击者的技能和想象力的限制,在较小程度上,受到纵深防御对策的限制,例如与数据库服务器的低权限连接等。通常,将 SQL 注入视为高影响严重性。
SQL注入的影响范围
-
语言:SQL -
平台:任何(需要与 SQL 数据库交互)
SQL 注入已成为数据库驱动网站的常见问题。该漏洞很容易被发现,并且很容易被利用,因此,任何具有最小用户群的网站或软件包都可能受到此类攻击的尝试。
3SQL 注入的工作原理
可以使用 SQL 注入执行的攻击类型因数据库引擎的类型而异。该攻击适用于动态 SQL 语句。动态语句是在运行时使用 Web 表单或 URI 查询字符串中的参数生成的语句。
让我们考虑一个带有登录表单的简单 Web 应用程序。HTML 表单的代码如下所示。
<form action=‘index.php’ method="post">
<input type="email" name="email" required="required"/>
<input type="password" name="password"/>
<input type="checkbox" name="remember_me" value="Remember me"/>
<input type="submit" value="Submit"/>
</form>
上面的表单接受电子邮件地址,然后密码将它们提交给名为 index.php 的 PHP 文件。它有一个选项,将登录会话存储在cookie中。我们从remember_me复选框中推断出这一点。它使用 post 方法提交数据。这意味着这些值不会显示在 URL 中。假设后端用于检查用户 ID 的语句如下所示
SELECT * FROM users WHERE email = $_POST[’email’] AND password = md5($_POST[‘password’]);
-
上面的语句直接使用 $_POST[]
数组的值,而不对其进行加工。 -
密码使用 MD5 算法进行加密。
现在让我们用第三方网站快速模拟一下SQL语句执行的场景。网站:http://sqlfiddle.com/
CREATE TABLE `users` (
`id` INT NOT NULL AUTO_INCREMENT,
`email` VARCHAR(45) NULL,
`password` VARCHAR(45) NULL,
PRIMARY KEY (`id`));
insert into users (email,password) values ('[email protected]',md5('admim123'));
在左边的文本框内输入以上代码,然后点击Build Schema
select * from users;
在右边的文本框内输入以上查询语句,点击Run SQL
返回了以下信息:
假设用户使用[email protected] 作为账号和 admin123 作为密码。那么要对数据库执行的语句将是
SELECT * FROM users WHERE email = ‘admin@qianxin.com’ AND password = md5(‘admin123’);
可以通过注释掉密码部分并附加始终为真的条件来利用上述代码。假设攻击者在电子邮件地址字段中提供以下输入
[email protected]’ OR 1 = 1 LIMIT 1 — ‘ ]
生成的语句将如下所示。
SELECT * FROM users WHERE email = 'admim123'
OR 1 = 1 LIMIT 1 -- ' ] AND password = md5('123');
[email protected] 以单个引号结尾,该引号完成字符串引号 OR 1 = 1 LIMIT 1 是始终为 true 并将返回的结果限制为仅一条记录的条件。-- ' ]是消除密码部分的 SQL 注释。
复制上面的 SQL 语句并将其粘贴到 SQL Fiddle Run SQL 文本框中,如下所示返回来所期待的结果
没有输入密码,但是返回了密码
-
该语句智能地假定使用了 md5 加密 -
完成单引号和右括号 -
将条件追加到语句中,该条件将始终为 true 通常,成功的 SQL 注入攻击会尝试许多不同的技术(如上面演示的技术)来执行成功的攻击。
其他 SQL 注入攻击类型SQL 注入可能会造成更大的危害,而不仅仅是通过传递数据。一些攻击包括
-
删除数据 -
更新数据 -
插入数据 -
在服务器上执行可下载和安装恶意程序(如木马程序)的命令 -
将有价值的数据(如信用卡详细信息、电子邮件和密码)导出到攻击者的远程服务器 -
获取用户登录详细信息等
4SQL注入的预防
验证过程旨在验证是否允许用户提交的输入类型。输入验证确保它是可接受的类型、长度、格式等。只能处理通过验证的值。它有助于防止输入字符串中插入的任何SQL语句。在某种程度上,这类似于在开门之前通过猫眼看看谁在敲门。
验证不应仅应用于允许用户键入输入的字段,这意味着您还应该以相同的程度处理以下情况:
-
使用正则表达式作为结构化数据(如姓名、年龄、收入、调查回复、邮政编码)的白名单,以确保强大的输入验证。 -
如果是一组固定的值(如下拉列表、单选按钮),请确定返回哪个值。输入数据应与提供的选项之一完全匹配。
下面显示了如何表名验证。
switch ($tableName) {
case 'fooTable': return true;
case 'barTable': return true;
default: return new BadMessageException('unexpected value provided as table name');
}
然后,可以直接追加$tableName变量——它是表名的合法值和预期值之一。
对于下拉列表,验证数据非常容易。假设希望用户选择从 1 到 5 的分数,可以将 PHP 代码更改为如下所示:
<?php
if(isset($_POST["selRating"]))
{
$number = $_POST["selRating"];
if((is_numeric($number)) && ($number > 0) && ($number < 6))
{
echo "Selected rating: " . $number;
}
else
echo "评分必须是 1 到 5 之间的数字!";
}
这里添加了两个简单的检查:
-
必须是一个数字(is_numeric()函数)。 -
要求$number大于 0 且小于 6,这样范围为 1–5。
必须验证从外部各方接收的数据。该规则不仅适用于网站的输入,也适用于供应商、合作伙伴、销售商或监管机构。这些供应商可能会受到攻击,甚至在他们不知情的情况下发送格式错误的数据。
参数化查询是预编译 SQL 语句的一种方法,以便您可以提供参数以便执行该语句。此方法使数据库能够识别代码并将其与输入数据区分开来。
用户输入会自动引用,并且提供的输入不会导致意图的更改,因此此编码样式有助于缓解 SQL 注入攻击。
可以将参数化查询与 MySQLi 扩展一起使用,但 PHP 5.1 在处理数据库时提供了一种更好的方法:PHP 数据对象 (PDO)。PDO 采用简化参数化查询使用的方法。此外,它使代码更易于阅读和更具可移植性,因为它在多个数据库上运行,而不仅仅是MySQL。
此代码使用带有参数化查询的 PDO 来防止 SQL 注入漏洞:
<?php
$id = $_GET['id'];
$db_connection = new PDO('mysql:host=localhost;dbname=sql_injection_example', 'dbuser', 'dbpasswd');
//准备查询
$sql = "SELECT username
FROM users
WHERE id = :id";
$query = $db_connection->prepare($sql);
$query->bindParam(':id', $id);
$query->execute();
//获取结果
$query->setFetchMode(PDO::FETCH_ASSOC);
$result = $query->fetchColumn();
print(htmlentities($result));
存储过程 (SP) 要求开发人员将一个或多个 SQL 语句分组到一个逻辑单元中,以创建执行计划。后续执行允许自动参数化语句。简而言之,它是一种可以存储以供以后使用并多次使用的代码类型。
因此,每当需要执行查询时,只需调用存储过程,而不是一遍又一遍地编写查询。
下面是在MySQL服务器中创建存储过程的过程。例如,有一个如下所示的表:
CREATE TABLE `salary` (
`empid` int(11) NOT NULL,
`sal` int(11) DEFAULT NULL,
PRIMARY KEY (`empid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
假设有一名员工需要从该表中获取有关公司工资的聚合数据。首先,您需要创建一个用户"tr":
CREATE USER 'tr'@'localhost' IDENTIFIED BY 'mypass';
该用户只需要对表所在的架构具有 EXECUTE 特权:
grant execute on hris.* to tr@`%`
SP 的创建方式如下:
DELIMITER $$
CREATE PROCEDURE `avg_sal`(out avg_sal decimal)
BEGIN
select avg(sal) into avg_sal from salary;
END
发出命令的过程将创建avg_sal SP
,它将存储在数据库中,随时可以调用。
要从 PHP 应用程序调用 SP,可以使用 PDO:
$db_connection = new PDO('mysql:host=localhost;dbname=hris', 'tr', 'mypass');
$query = $db_connection->exec('call avg_sal(@out)');
$res = $query->query('select @out')->fetchAll();
print_r($res);
$res
将根据用户的请求显示平均工资。然后,用户可以使用PHP执行输出过程。
SP 现在连接用户(员工)和表(工资),用户无法直接访问,使其成为数据库安全中必不可少的资产。
始终对每个数据库管理系统 (DBMS) 提供的用户输入使用字符转义函数。这样做是为了确保DBMS永远不会将其与开发人员提供的SQL语句混淆。
例如,在 PHP 中使用 mysql_real_escape_string() 来避免使用可能导致意外 SQL 命令的字符。登录绕过方案的修改版本如下所示:
$db_connection = mysqli_connect("localhost", "user", "password", "db");
$username = mysqli_real_escape_string($db_connection, $_POST['username']);
$password = mysqli_real_escape_string($db_connection, $_POST['password']);
$query = "SELECT * FROM users WHERE username = '" . $username. "' AND password = '" . $password . "'";
进行小的更改将防止非法 SQL 注入。
避免管理权限不要使用具有 root 访问权限的帐户将应用程序连接到数据库。只有在绝对需要的情况下才应执行此操作,因为攻击者可以访问整个系统。即使是非管理帐户服务器也可能给应用程序带来风险,如果数据库服务器由多个应用程序和数据库使用,则风险更大。
因此,最好对数据库强制实施最小特权,以保护应用程序免受 SQL 注入的影响。确保每个应用程序都有自己的数据库凭据,并且这些凭据具有应用程序所需的最低权限。
与其尝试确定应取消哪些访问权限,不如专注于确定应用程序需要哪些访问权限或提升的权限。如果用户只需要访问某些部分,则可以创建严格执行此功能的模式。
5总结
SQL 注入是一种利用错误 SQL 语句的攻击类型 SQL 注入可用于绕过登录算法,检索、插入、更新和删除数据。SQL注入工具包括SQLMap,SQLPing和SQLSmack等。编写 SQL 语句时良好的安全策略可以帮助减少 SQL 注入攻击。
6写在最后
关于公众号
HackerDo安全专注于收集最新网络安全消息,发布各类漏洞信息以及修复方案,关注各大比赛,及时带来最新动态以及知识教程。我们会不定期分享漏洞PoC以及知识干货,不定期送出福利。
微信交流群
如果失效请在后台回复“粉丝群”获取最新加群方式!
QQ社区群
原文始发于微信公众号(HackerDo安全):SQL注入一文快速了解:介绍、注入和预防
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论