SQL injection***原理

这篇是sql注入基础内容,目的是能了解注入的基本原理,并不涉及到具体的***,这也是个人学习笔记,如有不足和错误之处忘看客指正heyihome.blog.51cto.com

一、什么是SQL injection

通常大家都知道除了一些静态页面站点外,如今网络上大量网站需要使用数据库,并且用户的种种操作都会与其产生交互。比较典型的就是用户名、密码输入登陆,还有电子商务网站购物也需要同数据库交互查询商品信息等,而SQL注入***就是在正常的交互中插入恶意数据格式和请求来达到***目的。

二、哪里使用注入***

WEB应用向后端数据库提交输入时,就是容易遭受***的时候,通常多数SQL注入***是在URL里面输入,也可以在表格域和其他一些动态生成的SQL查询语句的输入参数。

三、***实施原理

让我们先从基本的sql查询语句开始

Seclect somedatacolumn,someotherdatacolumn FROM somedatadasetable where someconditionismet

上面这段就是一条标准的SQL查询语句,查询 某字段 从  哪个表 匹配条件是什么。

例如SQL在电子商务网站上应用,当需要查询某产品信息时,应用程序通过CGI参数建立链接,在其查询中引用,链接通常看起来如下:

http://www.xxxxx.cn/shop_view.asp?id=35

其应用程序需要知道用户希望看到那类商品,所以浏览器会发送一个标识符,这里为“id”,然后应用程序动态将其包含在SQL查询请求中,以便能在数据库中匹配到对应的数据,其在后台的解释可能如下:

这样看起来应该是没任何问题的,那么风险在哪里呢?假设如果我们是在某论坛登录,那么在后台的SQL查询中,语句应该是这样的:

Seclet name.picture,description,price FROM Products Where ID=35

其中被引号框入的数据就是用户在论坛登陆时输入的用户名和密码,假设有个恶意用户想盗取我们的用户名和密码登录,那么他需要知道正确的namepassword才可登录。但如果这个站点存在sql注入漏洞会如何呢?

例如论坛有zhangsan这个用户,我们在用户帐号的表格域中输入 zhangsan' -- (-- 为注释符,双虚线),那么在后台sql查询中将出现如下语句

Seclet accountdate FROM accountinfo Where accountid = 'anaccountnumber' AND password = 'apassword'

因为“--”为注释符,那么语句后面的内容都被忽视,实际不做检查,其实际查询的语句就成了

这样结果是什么,我们没输入密码,但通过认证进行了登录。

Tipe:输入时在用户后使用了单引号,这个引号是做为sql查询请求的以部分,这就意味可以改变提交到数据库的查询语句结构。但注意,由于我们使用了单引号,在SQL中引号中必须包含字符串。如果是用整数型数据查询,那么就不用必须输入单引号了

从上面的结果中可以看到,通过注释符跨过了对密码的认证,但前提是知道用户名才可以,如果我们做下变动,想获取全部用户信息呢?我们需要提交这样一条语句

Seclet accountdate FROM accountinfo Where accountid = 'zhangsan' --' AND password = 'password'

这句话意思是只要为真,就查询所有用户信息,其实现如下,account部分可以用单引号来屏蔽web程序生成匹配好的单引号,True条件可以1=12>1这类含义数学运算。(有些数据库支持直接输入 true),为此输入

' OR 1=1 --

在后台sql查询语句就变成如下了,导致返回了数据库所以用户ID信息

Seclet accountdate FROM accountinfo Where accountid = 'zhangsan'

这个例子在web源代码通常是这类形式:

Seclet accountdate FROM accountinfo Where accountid = '' OR true

Seclet accountdate FROM accountinfo Where accountid = '' OR 1=1

$SQLquery = "seclect * from users where username = ' ".$_POST["username"]." ' and password = ' ".$_POST["password"]." ' ";

$DBresult = db_query($SQLquery);

If($DBresult){

// username + password is correct --- log the user in

}

Else{

// username or password was incorrect

}

从以上代码可以看出来,由于我们输入的字符串导致返回多行数据,DBresult变量将为一个正数,由此通过了认证。这个例子危险在于对数据没有进行验证,因为在sql注入中总是会有一些返回值回来。这个例子中web应用接收数据时会得到数据库中所有数据的第一行。

这里有个假设前提为开发者使用第一条记录来确定对用户的判断,这是常用编程技巧,因为正常操作中只返回第一行。但刚才所使用字符串导致返回多行数据,由于在用户列表信息中通常第一行都是admin帐号,所以这里会导致我们可以用admin帐号直接登录系统,而不需要知道用户名和密码。

如果对上述***进行扩展,使数据库能执行更多的操作,那么就需要用到分号执行附加命令,例:

这样就在数据库中增加了lisi这个帐号。不过注意的是,这样做不代表能登录系统,因为除了用户名密码外,一个完整的帐号信息还包含权限等等内容,这些需要知道数据库表内的列和字符格式,这个一般很难能知晓。但如果利用数据库返回的错误信息,可以了解更多数据库的组成。

除了INSERT插入数据,还可以用DROP TABLE直接破坏数据库。

四、防范方法

避免注入需要开发对各类特色字符进行过滤,在url、表格域、等在用户可控制输入的地方,只要于SQL语法相关的特殊字符和保留字应该在提交到数据库之前进行过滤掉。其过滤操作应在服务器端进行,如果是在客户端执行的HTML中,会给用户机会去修改验证程序来绕过验证。

在建立数据库时也应该根据用户对数据的操作需求,来赋予不同的权限,这样即便发生了SQL注入***,也会让其限制在那些被正常访问到的数据中。例如管理员可能需要对帐号具有读取写入权限,但普通用户就不应该有这样的权限。

By 何艺 ver1.0

2011-1-15