• 基于约束的SQL攻击


    前言

    值得庆幸的是如今开发者在构建网站时,已经开始注重安全问题了。绝大部分开发者都意识到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     ';
    1. 但也存在异常情况,最好的例子就是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. 为了更加安全,还可以用手动调整输入参数的限制长度(依照数据库设置)

    文章参考自:https://dhavalkapil.com/blogs/SQL-Attack-Constraint-Based/

  • 相关阅读:
    make、make clean、make install、make uninstall、make dist、make distcheck和make distclean
    Eclipse开发C/C++ 安装配置
    没有文件扩展“.js”的脚本引擎问题解决
    Linux目录架构详解
    Linux查看硬件信息以及驱动设备的命令
    23种设计模式彩图
    ACE在Linux下编译安装
    void及void指针含义的深刻解析
    centos7.x设置nginx开机自启动
    Centos7防火墙关闭和启用iptables操作
  • 原文地址:https://www.cnblogs.com/ECJTUACM-873284962/p/8977983.html
Copyright © 2020-2023  润新知