SQL注入——入门篇

SQL 注入的定义

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。 —— [ 百度百科 ]

网页链接存在参数传递,后台并没有对用户的输入进行过滤,导致用户的输入直接被SQL解释器执行。SQL注入的产生条件

  • 有参数传递
  • 参数值带入数据库查询并且执行

举个简单的例子:

  • A www.test.com/index.php?id=1
  • B www.test.com/index.php
  • C www.test.com/index.php?id=1&parm=3

这里,A把参数值1赋值给参数‘id’,并且传到index.php的网页中,达到相应的效果。那么,就有可能存在注入漏洞。同样的道理,C也有可能存在注入漏洞,因为其解析了两个参数值。而B只是对一个网页进行简单的访问,并没有涉及到参数的传递。

我们这里只是在网页链接上,对SQL注入进行浅显易懂的解释,事实上也有一些SQL注入并不会显示在链接地址上,这就需要分析网页的源代码,才能定位到相应的漏洞,这方面的进阶,我们以后再加以叙述。

原理分析

我们以DVWA平台分析SQL注入产生的原因,DVWA的搭建过程,可自行参考网上教程。
当用户在User ID的文本框中输入 ID,点击提交,网页就会以GET方式把用户刚刚的输入提交到后台,并且进行相应的查询。

当用户在User ID的文本框中输入ID,点击提交,网页就会以GET方式把用户刚刚的输入提交到后台,并且进行数据库查询,查询结果又会返回在前端页面下。我们来分析以下源码,以帮助我们更好的了解SQL注入形成的原因。

<?php     
if(isset($_GET['Submit'])){ 

    // Retrieve data 
    // 用$符号定义一个变量,叫id,预定义的$_GET变量用于收集来自表单‘id’的值,也就是说用户在网页后缀提交的id=1,数字1最终会赋值给$id

    $id = $_GET['id'];       
    $getid = "SELECT first_name, last_name FROM users WHERE user_id = '$id'";

    // 执行SQL语句,在这两句代码中,我们可以看到,用户提交的id未经任何过滤,直接赋值到SQL语句中

    $result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' ); 

    $num = mysql_numrows($result); 

    // 以下代码是服务器返回给前端的查询结果,可暂时忽略
    $i = 0;
    while ($i < $num) { 

        $first = mysql_result($result,$i,"first_name"); 
        $last = mysql_result($result,$i,"last_name"); 

        echo '<pre>'; 
        echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last; 
        echo '</pre>'; 

        $i++; 
    } 
} 
?>

从以上代码的注释分析,可以看出,用户提交的数据并没有进行过滤。如果用户提交的不仅仅是一个id,而是一段标准的SQL语句,那么会被SQL解释器执行。例如输入1‘ and 1=1 order by 4 #,那么上述代码中的SQL语句就会变为

$getid = "SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1 order by 4 #'";

#号将后续的引号注释了。order by 是用来查询列数的,当字段数超过数据库的字段数,数据库就会返回错误信息,因此,我们可以利用order by来猜测数据库的字段数。至此,如果熟悉SQL语句,那么可以进一步写入更多的语句,查询数据库,导致隐私数据泄露。

注入过程

漏洞判断

  • 1.判断网页链接的格式是否符合我们一开始提出的SQL注入产生的条件
  • 2.使用常见的 and 1=1 或者 单引号’ 来判断用户的输入是否被SQL解释器执行。

-比如:1’ and 1=1 #,同样的,我们带入到网页的源码中,

$getid = "SELECT first_name, last_name FROM users WHERE user_id = '1' and 1=1 #'"

and 1=1 是一个逻辑判断语句,也就是说,因为 1=1,所以前面的SQL语句查询,可以执行。
那么如果换成 and 1=2,很明显,逻辑判断不成立,所以前面的SQL语句无法查询,网页返回错误信息。

查询数据库名称

  • 联合查询法
  • 逐字猜解法

在这里,我们输入 1’ union select 1,database() #,就可以在网页前端返回数据库名称。
这里写图片描述

这里的dvwa就是指数据库的名字叫dvwa。至于为什么可以查询到名称,刚刚我们已经有过类似的分析,读者可自行将我们的输入带入到网页源码。database()在SQL语句中,就是指数据库的名称。

查询数据库表名

输入1’ union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #

  • group_concat() 是一个函数,将同一个id的其他字段合并起来。 table_name,顾名思义,就是表名的意思。
  • information_schema.tables 是MySQL提供的自带的数据库,主要是提供用户自行建立的一些表的信息。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等。
  • table_schema=database() 是指数据库名称为database()。

这里写图片描述
说明dvwa数据库中,一共有两个表,分别为guestbook和users。

获取字段名

输入1’ union select 1,group_concat(column_name) from information_schema.columns where table_name=’users’ #
这里写图片描述
查询成功后,可以看到users表中的字段有user_id, first_name, last_name, user…

获取数据库的详细内容

输入1’ or 1=1 union select group_concat(user_id,first_name,last_name),group_concat(password) from users #
这里写图片描述
最终,我们得到数据库的详细内容。

防御SQL注入

归根到底,需要对用户的输入进行过滤,因为在Web攻防中,我们永远不要相信用户的输入 1
1.使用预编译语句,绑定变量。
2.使用安全的存储过程对抗SQL注入。
3.检查数据类型。
4.使用安全函数。

总结

在此篇文章中,我们对SQL注入进行实际的分析,并以awvs作为试验平台。通过一个简单的小试验,希望大家对SQL注入能够有一个更加清晰的认识和了解。当然实际注入过程,我们可以借助自动化平台或软件实现,如Sqlmap、穿山甲、啊D注入等等工具。最后,简要说明几种常见的防注入方法。


  1. 吴翰清. 白帽子讲Web安全[M]. 电子工业出版社, 2014.
发布了23 篇原创文章 · 获赞 22 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/song_lee/article/details/80971459