SQL 注入原理


SQL注入原理

前言

不管是什么语言编写的 WEB 应用,他们都有一个共同的特点,具有交互性并且多数都是数据库驱动。在网络中,数据库驱动的 WEB 应用场景随处可见,由此而存在的 SQL 注入是影响企业运营且最具破坏性的漏洞之一,这里想问一句,我们就真的是了解什么是SQL 注入吗?

注入的原理

什么是 SQL?

SQL 是一门 ANSI 的标准计算机语言,用来访问和操作数据库系统。SQL 语句用于增删改查数据库中的数据。SQL 可与数据库程序协同工作,常见数据库比如 MS Access、DB2、Informix、MS SQL Server、Oracle、Sybase 以及其他数据库系统。

什么是 SQL 注入?

看起来很复杂,其实很简单的就能解释,SQL 注入就是一种通过操作输入来修改后台的 SQL 语句来达到恶意 SQL 代码执行进行攻击目的的技术。

SQL 注入是怎么形成的?

构造动态字符串是一种编程技术,它允许开发人员在运行过程中动态构造 SQL 语句。开发人员可以使用动态 SQL 来创建通用、灵活的应用。动态 SQL 语句是在执行过程中构造的,它根据不同的条件产生不同的 SQL 语句。当开发人员在运行过程中需要根据不同的查询标准来决定提取什么字段( 如 SELECT 语句),或者根据不同的条件来选择不同的查询表时,动态构造 SQL 语句会非常有用。

在 PHP 中动态的构造 SQL 语句字符串。

$query = "SELECT * FROM user WHERE username = ".$_GET['id'];

从上面的代码我们可以控制输入参数 id 修改所要执行的 SQL 语句的逻辑,进而达到攻击的目的。

编写一个注入点

首先介绍一些基础知识,为了方便学习。

SQL SELECT 语法
SELECT 列名称 FROM 表名称; — 符号 * 取代列的名称是选取所有列
WHERE 子句
如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句。
SELECT 列名称 FROM 表名称 WHERE 列 运算符 值

好,我就默认你已经了解了一些基本的 SQL 语句,所以我就直接开始编写一个基本的 SQL 注入点的程序。

  1. 第一步就是判断一下变量是否初始化
<?php
if (isset($_GET['id'])) {
    // code 
}
  1. 第二步就是链接数据库,在 PHP 代码中这个任务可以通过一下的代码来实现
mysqli_connect(servername, username, password);
	servername: 可选,设定想要连接的数据库,默认是 `localhost:3306`
	username:   可选,设定登陆使用的用户名,默认是拥有此进程的用户
	password:   可选,设定连接数据库的密码,默认是""
  1. 链接成功后,需要选择一个数据库
mysqli_select_db(connection, databasename)
	databasename: 想要选择的数据库
	connection: 设定数据库链接,默认为上一个连接
  1. 选择完数据库,我们需要执行一条 SQL 语句查询
mysqli_query(query, connection)
    query: 设定要执行的 SQL 语句
    connection: 设定数据库链接,默认是上一个链接
  1. 查询完成对返回的结果做处理
mysqli_fetch_array(data, array_type)
    data: 设定使用的数据指针,默认是 mysqli_query 函数产生的结果
    array_type: 设定结果的返回类型
  1. 完整结果
<?php
if (isset($_GET['id'])) {
    $connection = mysqli_connect('localhost', 'root', 'root');
    if (!$connection) {
        die("Couldn't connect to database: " . mysqli_error($connection));
    }
    // select db
    mysqli_select_db($connection, 'demo');
    $query = "SELECT * FROM users WHERE id = " . $_GET['id'];
    echo $query;
    echo "<br>";
    $sql = mysqli_query($connection, $query);
    $result = mysqli_fetch_array($sql);

    echo "<table class='itable' border='1' cellspacing='0' width='300px' height='150'>";
    echo "<tr><td>id</td><td>username</td></tr>";
    echo "<tr><td>" . $result['id'] . "</td><td>" . $result['username'] . "</td></tr>";
    echo "</table>";
    mysqli_close($connection);
}

准备工作

代码层工作已经做好,但是在数据库里面,我们还没有 demo 这个数据库啊,接下来我就带大家一步步创建数据库,创建表,创建列,插入数据。

  1. 创建数据库
  2. 创建数据表 users 和列 id,username,password
  3. 随便插入几条数据

寻找及确认 SQL 注入

推理测试法

寻找SQL 注入漏洞有一种很简单的方法,就是通过发送特殊的数据来触发异常。首先我们需要了解数据是通过什么方式进行输入,这里我总结了三个:

  • GET 请求:该请求在URL 中发送参数。
  • POST 请求:数据被包含在请求体中。
  • 其他注入型数据:HTTP 请求的其他字段也可能会触发 SQL 注入漏洞。

了解完数据的输入方式,我们接下来再学习数据库错误。这里我们以MySQL 为例,其它的请大家自行学习咯。我们现在参数后面加个单引号,如下图:

SQL 语句最终就变成 select * from users where id = ,执行失败,所有 mysqli_query 函数返回来一个布尔值,在下行代码中 mysqli_fetch_array 将执行失败,并且 PHP 会显示一条警告信息,告诉我们 mysqli_fetch_array 的第一个参数必须是个资源,而代码在实际运行中,给出的参数值却是一个布尔值。所以为了更好地了解这个报错。可以在:

$sql = mysql_query($query,$connection);
// 添加下面
if(!$sql)
{
die('<p>error:'.mysql_error().'</p>');

这样当应用捕获到数据库错误且SQL 查询失败时,就会返回错误信息:(我们在参数中添加单引号返回的错误信息)

error:You have an error in your SQL syntax; check the manual thatcorresponds to your MySQL server version for the right syntax to
use near ‘’’ at line 1

然后借助这些错误,我们这可以推断应该存在SQL 注入。还有其他数据库错误信息,以及MySQL 其他错误信息,由于篇幅问题就不一一讲解了

and 大法和 or 大法

页面不返回任何错误信息,我们就可以借助本方法来推断了,首先我们在参数后面加上 and 1=1 和 and 1=2 看看有什么不同。

and 1=1 and 1=2

可以发现 and 1=1 返回了数据,而 and 1=2 没有,这是由于 1=1 是一个为真的条件,前面的结果是 true,true and true 所以没有任何问题,第二个 1=2 是个假条件, true and false 还是 false,所以并没有数据返回。

好的,说完了 and,我们就看一下 or,or 就是或者的意思,就是两个都是假的才会是假的,我们先把 id 改成 5,可以发现是没有数据的,但是我们加上 or 1=1 之后就发现成功的反悔返回了数据,这是因为 1=1 为真,不管前面是不是假,数据都会返回,这样就把表里面数据全部返回,我们没看见,是因为代码中并没有迭代输出。这样,我们来修改一下代码。然后你就可以发现:

id=5 id=5 or 1=1

加法和减法

这里我们需要区分一下数字型和字符串型:

  • 数字型:不需要使用单引号表示
  • 其他类型:使用单引号来表示

综上所述,我们可以发现我们的例子都是数字型的,这样我们就可以使用加法和减法来判断了。(我又在表中添加了几行数据)。

加法

在参数中输入 1+1 看看返回的数据是不是 id=2 的结果,这里注意一下 + 在 URL 中是有特殊含义的,所以我们要对其进行 URL 编码,最后也就是 %2b

减法

一样的道理。


文章作者: Justice
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Justice !
  目录