您的位置:首页 > 数据库

SQL注入的方式与防治

2015-08-05 23:44 721 查看


所谓的SQL注入、XSS、溢出等的漏洞,归根到底,就是代码注入的问题,导致代码注入漏洞的产生的原因是因为代码和数据没有分离,即程序所处理的数据和程序的代码混在了一起,没有明确的区分。。。$oM>?h_

=

ok:L]8UN

3

而SQL注入产生的主要原因也就是用户所提交的数据被当作代码来执行,请看下面这个获取文章内容例子(省略了部分代码):$id=
$_GET["ID"];$sql = ‘SELECT * FROM article WHEREID=’.$id;$mysqli->multi_query($sql);?>注意看,当我们要查看这个某个文章的时候,就提交这个文章的ID(一般的网站对于这种请求都是使用GET请求的,即用户可轻易在URL上修改请求的内容。如果是POST请求的,可通过抓包改包或是修改网页内容进行修改请求),就会把SQL语句中的$ID变量赋值为当前用户提交的数据进行SQL查询。例如:当用户查看一篇ID为3的文章,那么此时的URL为X=abaKl

http://www.xxx.com/article.php?ID=3;k+?g­WZ

\

o3|4PAA/

此时服务器$_GET["ID"]所得的值就是3了。在经过SQL语句拼接之后,所得的SQL语句就变为Ri_2@

U-

SELECT * FROM article WHERE ID=3;@MTv4eC}e

­D84&=EpVZ

当然,这个是程序员所期望的实现的,但黑阔们看到的不是功能,而是漏洞!!o@.{|j

%dW

;P[0

因为存在SQL注入漏洞的关键条件是SQL语句拼接了用户能控制的变量,这个条件,在以上的例子中就符合了,所以黑阔完全可以提交恶意SQL语句与原请求的内容拼接成一个程序员完全没想到的恶意SQL语句提交给数据库引擎去执行。。。

R6fkc^

aZ_3@I{d`

假设黑阔在原本的URL后增加如下的语句:
­Nr$78]o9

;DROP TABLE admin–即原本的URL变为:http://www.xxx.com/article.php?ID=3;DROPTABLE
admin–注意,$_GET["ID"]此事的值就不再是3了,而是3;DROP
TABLE admin–了。那拼接后的SQL语句会是怎样的呢?!那就是:SELECT
* FROM articleWHERE ID=3;DROP TABLE admin–Y7p@NG&1q

3~3tjhw;]9

好了,那我们来分析一下这个SQL语句。。。K/N{F\

,C><n kx

首先,会执行:SELECT * FROM article WHERE ID=3,这是一个正常的SQL语句吧?!,是查询文章的内容的。问题是,执行完这个之后,会再执行:DROP
TABLE admin 而这个就是一个恶意的SQL语句了,它的作用是删除admin这个表,这样就导致数据库的数据丢失了,是一个非常危险的语句,同样的,我也可以删除article这个表,导致此网站所有的文章丢失!!很邪恶吧?!!当然,现在用multi_query函数的也比较少了,大多数都是用mysql_query函数,但别以为这样就可以防止SQL注入,因为提交的数据还是被拼接到了SQL语句中,只要构造好恶意的SQL语句,进行SQL注入也是轻而易举的。例如:在原本URL后加入
order by X(X是数字),就可以猜字段数,另外还可以加Union语句也可以做到语句的拼接进行攻击(需要SQL引擎版本的支持,Access数据库不支持),具体的一些攻击技巧,大家可以Google或百度一下,这方面的资料很多,我也没必要展开讲。。。 这也是一个典型的SQL注入的例子,但是现实中,有一大部分小白程序员都会写出这样明显的漏洞代码!!(注意这个语句后面的–,这是MYSQL语句中的注释,用于注释掉后面的内容,避免语句执行错误,因为黑阔一般情况下是不能准确的知道你的SQL语句的结构的)

$"|r7n5[

k]r4b`x`­

但是一般的黑阔是不会做这些的,因为做这些对他们自己没有任何益处,他们大部分的目的不是删除你网站的数据,而是要拿到这个网站的shell甚至是服务器权限。所以,他们通常会利用SQL注入去构造恶意语句来获取WEB管理员的后台帐号和密码,然后去登陆后台,进行进一步的渗透(如果数据库用户的权限足够高,黑阔可以直接获取系统权限),这里就不扩展了,有兴趣的童鞋可以Google或百度一下,这方面的资料也是很多的,咱们论坛也有不少。。。.|go$}Fk

再来看一个很经典的SQL注入例子,那就是万能密码。或许有些人会觉得,万能密码的问题怎么和SQL注入扯一起了呢?!事实上,出现万能密码这种漏洞,本质就是SQL注入,这在
代码注入(番外篇)上已经总结过了,我就不再总结了,直接复制过来吧。。。N1c

0

>{

FA{Q6fi:2

看产生万能密码的漏洞代码:e_|<tYx‑><

f9>pMfi:@

$username = $_POST["username"]; X=m^+%iD

$password = $_POST["password"]; H3R{+7

$result = mysql_query(“SELECT * FROM Users where UserName=’$username’ andPassWord=’$password’”);9%NsW3

|

if(mysql_num_rows( $result ) > 0){echo ‘alert(“login is true!”);5&EBU

l}

​window.location = “index.php”’;}qQDe'f~

[D

eD‑U:

当黑阔提交 ‘or 1=1–
(万能密码)的时候,提交的内容被注入到SQL语句中,这时候有几种情况,这里列举两个:_)=­
e`9%

1. 当黑阔猜测用户名为admin,密码提交万能密码的时候,SQL语句变为:j~ds)dW%`&

SELECT * FROM Users where UserName=’admin’ and PassWord=”or 1=1–’2Ul8<${c{

>S}‑X)4

此时,where限定的是
UserName内容为admin,PassWord为空才进行返回(这两个限定条件用and连接),但是注意后面有一个or
1=1。;Krs*3 s

O-p`9(_m

通过逻辑的处理,我们知道这个限定条件的意思是:当UserName为admin和PassWord为空或者1=1时就进行返回查询信息e&i`/m5

fP4P'e‑I

所以关键就是or这个逻辑,导致前面的限定都行为虚设。
9Ca0Tu

1QmOUw}yj

至于or 1=1后面–,在SQL语句中,–为注释,也就是注释掉最后的’,避免执行语句错误;/4x.t#b

X0j>g^b8

最后返回给 $result变量的是Users表的内容,然后就进行判断$result的数组是否为零,如果大于零,则认为是登陆成功Ue;Z)}­

V73/q

因为Users表中已经有用户了,所以返回的数组肯定不为空,所以肯定可以登陆,代码如下:if(mysql_num_rows($result
) > 0){echo ‘alert(“login is true!”);window.location =“index.php”’;}最后就登陆成功的~
~e,l2

­<

‑"S'

Yn-

2. 当黑阔提交用户名和密码都为万能密码(’or 1=1–)的时候与1中类似,SQL语句变为如下:tXrKC

vmNI$

KZM

SELECT * FROM Users where UserName=”or 1=1–’ and PassWord=”or 1=1–’与1中不同的是,–符号在UserName中就出现了,所以后面的语句已经被忽略了
oBub]<.J

wS,fj gX

SQL语句的逻辑变为:当UserName为空或者
1=1时就进行返回查询信息然后与1中一样,返回了Users表中的内容给$result变量,再进行判断,然后就登陆成功了。。。*v8daF

l\N2C‑4NG

这里讲了两个SQL注入的例子,或许你以为SQL注入只存在于WEB端,对服务器没有直接的影响,但如果你这样想,那就错了!!
如果权限处理不当,一个SQL注入点就可以直接导出Shell,甚至是在服务器上执行任意命令!!而据我所知,这些权限处理不当的服务器在互联网中也不占少数,所以希望各位程序猿、网站管理员等的引起足够的重视!!rrgOp5aV"

^a/q6{

好了,上面已经分析了SQL注入产生的原因,那下面就讲如何防御了!
&k_L

K

PvW4%A@0

SQL注入是一个发现于1998年,可以说是属于上世纪的漏洞了,但现在仍然有不少的网站存在着这样的漏洞,是这种漏洞很难防御吗?!!lJfk4
-;M

BaP'y8dVN

答案是否定的,从理论上来说,只要防御方式恰当,SQL注入是可以杜绝的。而我们要防御SQL注入,要做的事就是先把所有可能存在SQL注入的地方都找出来,然后逐个修复,切忌不能因为觉得某个注入点难以挖掘而忽视不管,这样你就轻视了黑阔了!一旦这个注入点被挖掘,你之前做的所有工作都可以说是白费了,这也是平常我们所说的“木桶原理”。4=y&}3om(0

|XN w&X1VF

防御SQL注入的要点:1.不要信任任何用户提交的数据2.使用白名单原则进行过滤,黑名单不靠谱,这也是做安全所必须知道的3.SQL语句要尽量避免使用字符串拼接的形式,强烈建议使用查询参数化(绑定变量)的方法进行查询4.数据库应遵循“最小权限”原则5.数据类型检测,不同数据类型进行不同的过滤对于第一点,准确来说是:任何经过了客户端的数据都不能信任,因为黑阔还可以通过抓包改包的方法修改一些浏览器不能修改的数据,而这些也是程序猿经常忽略的地方!!对于第二点,采用白名单而不用黑名单,这是我在刺总的《白帽子讲WEB安全》上觉得收获最大的一个思想,也是安全圈子的常识了!!
因为黑名单原则在无数的例子前面已经突出了它明显的不足之处。例如,过滤一处SQL注入点,采用黑名单过滤了and这个SQL保留字,但我可以把and改为aNd来绕过过滤机制。可能你会说,那我把所有的可能都过滤了,不就行了?!对于这个想法,第一,工作量非常大,而且容易遗漏;9qGba=}Ey

jHHCJOHB8

第二,随着数据库版本的更新,可能会出现一些新的保留字,而你又不能及时的过滤,就可能造成悲剧滴发生。。。所以,能不用黑名单过滤就尽量避免!
=\5f_g2M

H13\8Te{

对于第三点,上面的两个例子都已经说明SQL语句使用字符串拼接的方法很可能会造成SQL注入的发生了,所以我们要尽量避免使用这样的字符串拼接的方式。。。这里强烈建议使用查询参数化(绑定变量)的方法进行查询,这也是刺总所推荐解决SQL注入的方法。。。
从安全的角度来说,查询参数化有效解决SQL注入的问题;从开发的角度来说,还可以提高SQL查询的性能,可以说是一举两得的方法。。。GCr]x
'

x)$0Nr62D

对于第四点,其实做安全时,任何涉及到权限的问题时,都应该遵循这个“最小权限”原则。即只要给程序所需的权限即可,多余的权限都CUT掉,这样就可以防止一些因为权限过大所出现的安全问题,就例如上面说提到的,利用SQL注入e~'z;%

O~

Q3

bU"f

导出Shell甚至在服务器执行任意命令。。。对于第五点,可能很多程序猿都有这么一个误区,就是只要对用户提交的数据进行mysql_real_escape_string()或是addslashes()处理就可以进行安全的SQL查询了(包括一些专业的文档也这么说)。。。f2Xn!]o

- 3PLP$P

那我们来看下mysql_real_escape_string()会对哪些字符进行转义: ’ ” \r
\n NULL Control-Z上面列举的是mysql_real_escape_string()会进行转义的(addslashes()就不进行讨论了,因为addslashes()转义的比这个函数还要少),那来看下刺总在他书上举的一个例子:http://www.xxx.com/user.php?id=12,AND,1=0,union,select,1,concat(user,0x3a,password),3,4,5,6,from,mysql.user=substring_index(current_user(),char(64),1)以上这个例子就没用到
mysql_real_escape_string()转义的字符吧!!所以对于这种数值型的参数,不能用mysql_real_escape_string()进行转义,应该用intval()或是settype()进行数据类型的限定(当然这里说的是不用预编译的方法来进行SQL查询),其他的也是类似,但预防SQL注入不能单单靠数据类型的检测,还应该结合以上的一些方案好了,对于《WEB攻防系列之SQL注入》就告一段落了!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: