基于约束的SQL攻击

标签: WEB安全 | 发表时间:2017-01-06 08:24 | 作者:鸢尾
出处:http://www.freebuf.com

前言

值得庆幸的是如今开发者在构建网站时,已经开始注重安全问题了。绝大部分开发者都意识到SQL注入漏洞的存在,在本文我想与读者共同去探讨另一种与SQL数据库相关的漏洞,其危害与SQL注入不相上下,但却不太常见。接下来,我将为读者详细展示这种攻击手法,以及相应的防御策略。

注意:本文不是讲述SQL注入攻击

背景介绍

最近,我遇到了一个有趣的代码片段,开发者尝试各种方法来确保数据库的安全访问。当新用户尝试注册时,将运行以下代码:

  <?php
// Checking whether a user with the same username exists
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT *
          FROM users
          WHERE username='$username'";
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) > 0) {
    // User exists, exit gracefully
    .
    .
  }
  else {
    // If not, only then insert a new entry
    $query = "INSERT INTO users(username, password)
              VALUES ('$username','$password')";
    .
    .
  }
}

使用以下代码验证登录信息:

  <?php
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT username FROM users
          WHERE username='$username'
              AND password='$password' ";
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) > 0){
      $row = mysql_fetch_assoc($res);
      return $row['username'];
  }
}
return Null;

安全考虑:

  • 过滤用户输入参数了吗? — 完成检查

  • 使用单引号(’)来增加安全性了吗? — 完成检查

按理说应该不会出错了啊?

然而,攻击者依然能够以任意用户身份进行登录!

攻击手法

在谈论这种攻击手法之前,首先我们需要了解几个关键知识点。

  1. 在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”,对于绝大多数情况来说都是成立的(诸如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。

        SELECT * FROM users WHERE username='vampire     ';
    

    但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在“字符串比较”期间进行的。这是因为,SQL会在 内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。

  2. 在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“vampire”时,实际上只能插入字符串的前5个字符,即“vampi”。

现在,让我们建立一个测试数据库来演示具体攻击过程。

  vampire@linux:~$ mysql -u root -p
mysql> CREATE DATABASE testing;
Query OK, 1 row affected (0.03 sec)
mysql> USE testing;
Database changed

接着创建一个数据表users,其包含username和password列,并且字段的最大长度限制为25个字符。然后,我将向username字段插入“vampire”,向password字段插入“my_password”。

  mysql> CREATE TABLE users (
    ->   username varchar(25),
    ->   password varchar(25)
    -> );
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO users
    -> VALUES('vampire', 'my_password');
Query OK, 1 row affected (0.11 sec)
mysql> SELECT * FROM users;
+----------+-------------+
| username | password    |
+----------+-------------+
| vampire  | my_password |
+----------+-------------+
1 row in set (0.00 sec)

为了展示尾部空白字符的修剪情况,我们可以键入下列命令:

  mysql> SELECT * FROM users
    -> WHERE username='vampire       ';
+----------+-------------+
| username | password    |
+----------+-------------+
| vampire  | my_password |
+----------+-------------+
1 row in set (0.00 sec)

现在我们假设一个存在漏洞的网站使用了前面提到的PHP代码来处理用户的注册及登录过程。为了侵入任意用户的帐户(在本例中为“vampire”),只需要使用用户名“vampire[许多空白符]1”和一个随机密码进行注册即可。对于选择的用户名,前25个字符应该只包含vampire和空白字符,这样做将有助于绕过检查特定用户名是否已存在的查询。

  mysql> SELECT * FROM users
    -> WHERE username='vampire                   1';
Empty set (0.00 sec)

需要注意的是,在执行SELECT查询语句时,SQL是不会将字符串缩短为25个字符的。因此,这里将使用完整的字符串进行搜索,所以不会找到匹配的结果。接下来,当执行INSERT查询语句时,它只会插入前25个字符。

  mysql>   INSERT INTO users(username, password)
    -> VALUES ('vampire                   1', 'random_pass');
Query OK, 1 row affected, 1 warning (0.05 sec)
mysql> SELECT * FROM users
    -> WHERE username='vampire';
+---------------------------+-------------+
| username                  | password    |
+---------------------------+-------------+
| vampire                   | my_password |
| vampire                   | random_pass |
+---------------------------+-------------+
2 rows in set (0.00 sec)

很好,现在我们检索“vampire”的,将返回两个独立用户。注意,第二个用户名实际上是“vampire”加上尾部的18个空格。现在,如果使用用户名“vampire”和密码“random_pass”登录的话,则所有搜索该用户名的SELECT查询都将返回第一个数据记录,也就是原始的数据记录。这样的话,攻击者就能够以原始用户身份登录。这个攻击已经在MySQL和SQLite上成功通过测试。我相信在其他情况下依旧适用。

防御手段

毫无疑问,在进行软件开发时,需要对此类安全漏洞引起注意。我们可采取以下几项措施进行防御:

  1. 将要求或者预期具有唯一性的那些列加上UNIQUE约束。实际上这是一个涉及软件开发的重要规则,即使你的代码有维持其完整性的功能,也应该恰当的定义数据。由于’username’列具有UNIQUE约束,所以不能插入另一条记录。将会检测到两个相同的字符串,并且INSERT查询将失败。

  2. 最好使用’id’作为数据库表的主键。并且数据应该通过程序中的id进行跟踪

  3. 为了更加安全,还可以用手动调整输入参数的限制长度(依照数据库设置)

*参考来源: dhavalkapil,FB小编鸢尾编译,转载请注明来自FreeBuf(FreeBuf.COM)

相关 [约束 sql 攻击] 推荐:

基于约束的SQL攻击

- - FreeBuf.COM | 关注黑客与极客
值得庆幸的是如今开发者在构建网站时,已经开始注重安全问题了. 绝大部分开发者都意识到SQL注入漏洞的存在,在本文我想与读者共同去探讨另一种与SQL数据库相关的漏洞,其危害与SQL注入不相上下,但却不太常见. 接下来,我将为读者详细展示这种攻击手法,以及相应的防御策略. 注意:本文不是讲述SQL注入攻击.

SQL Server安全-加密术和SQL注入攻击

- Haipeng - 博客园-首页原创精华区
SQL Server上的加密术. SQL Server上内置了加密术用来保护各种类型的敏感数据. 在很多时候,这个加密术对于你来说是完全透明的;当数据被存储时候被加密,它们被使用的时候就会自动加密. 在其他的情况下,你可以选择数据是否要被加密. SQL Server可以加密下列这些组件:. ·存储过程,视图,触发器,用户自定义函数,默认值,和规则.

PHP代码网站防范SQL注入漏洞攻击的建议

- - BlogJava-qileilove
 所有的网站管理员都会关心网站的安全问题. SQL注入攻击(SQL Injection). 黑客通过SQL注入攻击可以拿到网站. 数据库的访问权限,之后他们就可以拿到网站数据库中所有的数据,恶意的黑客可以通过SQL注入功能篡改数据库中的数据甚至会把数据库中的数据毁坏掉. 做为网络开发者的你对这种黑客行为恨之入骨,当然也有必要了解一下SQL注入这种功能方式的原理并学会如何通过代码来保护自己的网站数据库.

PL/SQL动态SQL(原创)

- - ITeye博客
使用动态SQL是在编写PL/SQL过程时经常使用的方法之一. 很多情况下,比如根据业务的需要,如果输入不同查询条件,则生成不同的执行SQL查询语句,对于这种情况需要使用动态SQL来完成. 再比如,对于分页的情况,对于不同的表,必定存在不同的字段,因此使用静态SQL则只能针对某几个特定的表来形成分页.

Derby SQL 分页

- - ITeye博客
    之前在网上看到有人问 Derby SQL 分页实现的问题,网上有人给出这样的解决方案,SQL 如下:. 其实,这样的分页查询,性能不理想,我试过在 300W 数据量中采用这种分页方式,需要 20~30秒之久;其实 Derby 10.6 以上版本有更好的分页支持,直接给出 SQL 实现如下:.

SQL Server--索引

- - CSDN博客推荐文章
         1,概念:  数据库索引是对数据表中一个或多个列的值进行排序的结构,就像一本书的目录一样,索引提供了在行中快速查询特定行的能力..             2.1优点:  1,大大加快搜索数据的速度,这是引入索引的主要原因..                             2,创建唯一性索引,保证数据库表中每一行数据的唯一性..

MySql动态SQL

- - SQL - 编程语言 - ITeye博客
13.7. 用于预处理语句的SQL语法. MySQL 5.1对服务器一方的预制语句提供支持. 如果您使用合适的客户端编程界面,则这种支持可以发挥在MySQL 4.1中实施的高效客户端/服务器二进制协议的优势. 候选界面包括MySQL C API客户端库(用于C程序)、MySQL Connector/J(用于Java程序)和MySQL Connector/NET.

sql优化

- - 数据库 - ITeye博客
是对数据库(数据)进行操作的惟一途径;. 消耗了70%~90%的数据库资源;独立于程序设计逻辑,相对于对程序源代码的优化,对SQL语句的优化在时间成本和风险上的代价都很低;. 可以有不同的写法;易学,难精通. 固定的SQL书写习惯,相同的查询尽量保持相同,存储过程的效率较高. 应该编写与其格式一致的语句,包括字母的大小写、标点符号、换行的位置等都要一致.

birt动态SQL

- - ITeye博客
birt动态SQL实现有三种方式:拼接SQL、绑定变量和让应用程序拼接,birt得到返回结果集方式. 在数据集中写SQL,如下:. 选中数据集,点script方式,在beforeOpen事件中写如下SQL:. 然后就可以了,当然,也可以不写第一步,直接所有的SQL都在beforeOpen中拼接. 但是,拼接SQL方式不仅复杂容易错,还会导致SQL注入风险.

SQL Server 面试

- - SQL - 编程语言 - ITeye博客
在SQL语言中,一个SELECT…FROM…WHERE语句称为一个查询块,将一个查询块嵌套在另一个查询块的WHERE子句中的查询称为子查询. 子查询分为嵌套子查询和相关子查询两种. 嵌套子查询的求解方法是由里向外处理,即每个子查询在其上一级查询处理之前求解,子查询的结果作为其父查询的查询条件. 子查询只执行一次,且可以单独执行;.