sql注入原理及实验

来源:互联网 发布:网络安全管理系统 编辑:程序博客网 时间:2024/06/06 05:12

原理

可以将Web程序想象成一个图书馆管理员,它机械的听从用户告诉它的信息,在书库(sql程序)中查询(Select)信息
当你告诉它”三国演义”时,它会查找并告诉你书库中《三国演义》的信息
  这里的组合方式就是 书库中《[用户输入]》的信息
但是如果你告诉它”三国演义》或《所有书籍”,它机械地听从指令会查询并告诉你
  书库中《三国演义》或《所有书籍》的信息

究其原理,便是用户输入的”数据”被恶意构造成”操作”
上例的书名号就是用来区分书名(名词)和句子其他成分的,在程序中则是使用双引号来区分字符串和语句其他功能指令的

利用

这里拿一个WarGame作为例子:
http://natas14.natas.labs.overthewire.org/
username=natas14
password=Lg96M10TdfaPyVBkJdjymbllQ5L6qdl1
可以自己先试试~会了的话就不用看了0v0节省下好久时间呢!

打开以后发现是username和password的输入框,提供了服务器端的PHP源代码

<? if(array_key_exists("username", $_REQUEST)) { //检查$_REQUEST中是否存在key=username    $link = mysql_connect('localhost', 'natas14', '<censored>'); //连接mysql    mysql_select_db('natas14', $link); //选择数据库    $query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\""; //组成SQL语句字符串    if(array_key_exists("debug", $_GET)) { //如果$_GET中存在key=debug        echo "Executing query: $query<br>"; //将$query显示出来    }     if(mysql_num_rows(mysql_query($query, $link)) > 0) { //如果返回一条以上的数据            echo "Successful login! The password for natas15 is <censored><br>";     } else {             echo "Access denied!<br>";     }     mysql_close($link); //关闭mysql连接?> 

连接结构为:
  浏览器<————->PHP<————->mysql
  |客户端|    |---服务器---|

$query就是关键的sql语句
在php中它是一个作为连接函数的字符串参数,而输入mysql以后将成为一个sql命令
因此首先需要分析明确它的结构,这样才能方便我们之后的操作
假设令$_REQUEST={‘username’: ‘aaa’, ‘password’: ‘bbb’}时,$query和实际Sql语句分别是什么呢?
(建议看答案之前先自己尝试一下,提示:\是转义,’.’是PHP中的字符串连接符)
这里写图片描述

清楚了SQL语句的组成,我们就可以尝试发现PHP的漏洞了
很明显,双引号用来包裹两个变量,使其作为字符串类型的变量送入mysql
而知道了这一点,恶意令输入中带有双引号就会使得$query被送入mysql以后产生歧义:
试试令password= b” and True,会构造出怎样的SQL语句呢?
SELECT * from users where username = "aaa" and password="b" and True "
很明显,这是一句错误的SQL语句,因为双引号是单数个,就意味着肯定有字符串未闭合

说到这里,就要解释一下where子句的作用了:
Select语句在mysql数据库是查询检索的作用,where子句则是过滤条件
可以理解为

遍历所有数据项 if(数据项满足条件)Then       echo 数据项;

我们不知道username和password,所以没法让username=xxx and password=xxx成立
但是如果满足的条件恒真,那么mysql就会显示所有数据了
即令SQL语句为
SELECT * from users where True;

由于and和or优先级相同,因此它们依次从左向右运算
现有的语句为
SELECT * from users where False [] and False []
[]是我们可以注入的地方
那么很明显,or这个只要一侧为真,就令整个表达式为真的操作符就派上用场了
构造SELECT * from users where False and False or True就可以使运算后where恒真了

观察到$query后恒有一个双引号,因此不能简单地输入True,而是要构造能够合理包含尾双引号的语句,例如令password=b” or “1” = “1

生成的SQL语句就是:
SELECT * from users where username=”a” and password=”b” or “1”=”1”
很明显,where子句恒真,将会返回数据库内所有信息

防御

从SQL注入被发现到现在已有十几年的历史,在这个过程中黑客和开发者进行了大量的博弈
从最简单粗暴的检测用户输入中是否存在引号等非法字符,到从SQL解决问题的参数化查询
黑客同时也引入了构造绕过过滤的宽字节注入法等等

虽然参数化查询其实可以根本性地解决SQL注入的问题,不过由于开发者的水平问题,漏洞仍然层出不穷~
希望大家以后开发网页的时候要注意哦0 -

原创粉丝点击