杨 义 杨玉龙 张天然 李 帅
(贵州航天计量测试技术研究所,贵州 贵阳 550009)
B/S(Browser/Server)网络架构的出现,使得用户只需要一台能上网的电脑,就可以方便地在任何地方进行操作而不用安装任何专门的软件,但是随之而来的安全问题不断出现。最常见的就是SQL注入攻击,之所以SQL注入攻击如此常见,是因为它不需要攻击者有很深入的编程功底,只要能熟练使用SQL语言即可。SQL注入可以导致数据库系统中的普通用户窃取机密数据、进行权限提升等,具有很强的破坏性。
结构化查询语言(Structured Query Language)简称SQL,是一种用来和数据库交互的脚本语言,现今几大主流数据库都使用SQL语言。目前易受到SQL注入攻击的两大系统平台组合是:SQL Server+ASP和MySQL+PHP,SQL Server和MySQL作为关系型数据库,均采用SQL语言;ASP与PHP作为服务器端脚本语言,服务器端脚本程序是存在漏洞的,SQL注入攻击就是因此而存在的。而使用SQL Server+.NET系统平台组合相对安全些,因为.NET Framework开发提供了一系列的安全措施,如:.NET加密技术,.NET的基于角色的安全技术。
SQL注入问题受到开发者的广泛关注,2011年朱辉等提出了使用存储过程的方法可有效防止SQL注入攻击,但是没给出存储过程如何防止SQL注入的具体分析[3]。本文具体分析了存储过程可有效解决SQL注入问题,并指出其本质。同时提出了几点.NET开发中的安全措施,可以很大程度上增强系统的安全性。
2002年,Chris Anley将SQL注入定义为:攻击者通过在查询操作中插入一系列的SQL语句到应用程序中来操作数据。SQL注入攻击的基本思想:通过向用户输入的信息中注入一些额外的特殊字符或者SQL语句,使系统服务器端构造出来的SQL语句在执行时改变了查询条件,或者附带执行了攻击者想要执行的SQL语句。由此,攻击者获得数据库的操作权限,或者根据程序返回的结果,获得一些想知道的数据。
SQL注入主要是从SQL的语法中基于数据的应用程序存在的漏洞而存在的,因此而导致SQL注入攻击具有广泛性。理论上说,SQL注入攻击对于所有基于SQL语言标准的数据库软件都是有效的。下面给出一个简单的SQL注入攻击示例:
我们在经常使用某个系统或需要登录网站时,会通过表单的方式,提交自己的用户名(username)和密码(password),这时用户名和密码会被传递到Web服务器,在Web服务器端会进行有关SQL语句的重构,然后将重构的SQL传递给数据库服务器,在服务器端对SQL语句进行解析,返回查询结果,以此来判断是否允许登录。
一般在Web服务器端构造如下SQL查询语句:
select count(0)from user where username='"+username+"'and password='"+password+"'
假设数据库中存在用户“admin,123”,即用户名username为admin,密码password为123,系统会对用户名进行查询,判断是否存在该用户名的用户。但是,对于恶意攻击者来说不会这么输入,由于恶意攻击者不知道用户名和密码,通常会提交恶意数据,如:username=admin,password='321'or'1'='1'使得服务器构造的SQL查询语句变成select count(0)from admin where username='admin'and password='321'or'1'='1'。
因为'1'='1'恒为真,攻击者就可以绕过对密码的验证,只验证用户名,图1是SQL注入攻击的实例图。
图1 SQL注入攻击
图中显示了一般情况下的SQL注入攻击过程。为了获取更多的数据信息,攻击者会通过SQL的深层次注入攻击,在攻击中在数据库中添加自己的账户。
对于.NET开发初学者来说,很多人还停留在直接使用SQL语句访问数据库或者对数据库中的数据进行修改。这就给善于SQL注入攻击的攻击者带来了机会,目前对于SQL注入攻击的研究已比较深入。一般的SQL注入攻击防范方法总结如下:
2.2.1 WEB服务器的安全配置
(1)修改或者去掉WEB服务器上默认的一些危险命令,例如服务器安装之后的一些默认用户名和账户;
(2)屏蔽一些出错信息;
(3)配置目录的权限,分情况设置访问目录的权限,尽量不给写目录权限。
2.2.2 数据库的安全配置
(1)修改数据库的初始设置,修改或者去掉数据库系统安装之后产生的默认登录账户;
(2)及时升级数据库;
(3)限定WEB应用程序连接数据库的用户权限。
2.2.3 过滤特殊字符
(1)替换或删除敏感字符、字符串;
(2)使用变量代替字串,建立SQL查询,因为变量不是可以执行的脚本。
除了以上基本的防范措施,在系统开发中,使用存储过程来实现对数据库中数据的查询、删除、更新等操作将是更有效的防止SQL注入攻击方法。
存储过程是建立在数据库服务器端的SQL语句与部分控制流语句的预编译集合,通过将某些关于数据库操作的语言集中,交给SQL数据库服务器来完成特定的任务。
存储过程能有效提高系统的性能,主要是因为存储过程在经过第一次执行后,会把查询计划保留在内存中,以后在调用时,就无须进行编译,直接调用该存储过程。存储过程具有以下三个方面的优点:
(1)通过本地存储、代码预编译和缓存技术实现高性能的数据操作;
(2)通过通用编程结构和过程重用实现编程框架;
(3)通过隔离和加密的方法提高了数据库的安全性。
存储过程如何防止SQL注入攻击,以身份验证为例:
create procedure sp_getAdmin
(@adminName varchar(20),
@adminPwd varchar(50))
as
select count(0)from admin where adminName=@admin-Name and adminPwd=@adminPwd
go
在这个存储过程中可以看到有两个输入参数@admin-Name和@adminPwd,数据类型都为varchar,这里应用SQL注入攻击中常用的方法,在登录验证中提交adminName为admin'--,adminPwd为123。如果不用存储过程,验证语句为:select count(0)from admin where adminName='admin'--'and adminPwd='123',这时密码adminPwd参数因为“--”被解释为注释语句,从而在数据库服务器端就只对用户名进行验证,而不对密码进行验证。
上面@adminName与@adminPwd为存储过程参数,主要用于在存储过程和调用存储过程的应用程序或者工具之间传输数据。输入参数用于调用方法的数据值传递到存储过程,输出参数用于存储过程将数值或游标变量传递回调用方,它们被预先作为独立的数据体与SQL语句交互。
在上述sp_getAdmin存储过程中,输入参数@admin-Name和@adminPwd被当成两个独立的数据体和SQL语句交互,而不是与一般的SQL语句一样,将传进的参数与SQL语句重组。验证过程中,admin'--作为一个字符串传递给参数@username,123也作为一个字符串传递给参数@password。存储过程中的SQL查询语句不会重新组合为:select count(0)from admin where adminName='admin'--'and admin-Pwd='123',也就是“--”不会将后面的SQL语句注释掉,“ad-min'--”是一个整体。
因此存储过程验证用户名和密码,是有效的身份验证方法,在高效率访问数据库的同时,解决了SQL Injection攻击。但是使用了存储过程实现数据库操作之后,并不等于SQL注入攻击从此不会再出现。要使SQL注入攻击成为不可能,最终取决于服务器端调用存储过程的方式。针对不同的安全级别需求,还可以使用EXECUTE AS子句设定存储过程的安全上下文。
跨站脚本攻击(Cross Site Script Execution,XSS)指攻击者利用网页漏洞向客户端注入脚本代码,然后这些代码被发送到受信任的客户端上并被浏览器解释执行,攻击者利用这些代码盗取用户资料或利用用户身份对访问者进行病毒侵害。代码本身多用HTML和JavaScript编写,但也可能扩展到VBScript、ActiveX,或其它浏览器支持的技术。根据形成原因的不同,跨站脚本攻击可以分为三种攻击类型,分别是反射型XSS攻击、存储型XSS攻击和DOM型XSS攻击[5]。
为有效防止跨站脚本攻击,微软在ASP.NET 1.1之后的版本中都引入了对提交表单自动检测是否存在XSS的能力,但是很多程序员没意识到。当程序出现类似于HttpRequest-ValidationException或者“A potentially dangerous Request.Form value was detected from the client”的时候,很多程序员通过在ASP.NET页面的page中或者web.config配置文件中设置validateRequest=false来禁用这个特性,以达到解决问题的目的。但是这样做会使得ASP.NET的自动检测XSS功能失效,失去了安全保护措施。在.NET开发中,每一个标记的属性都有其特有的用处,在不了解的情况下,不要轻易修改。
使用存储过程加密技术,使得非系统维护者,无法修改数据库服务器中的存储过程。对于一般的企业,其数据库服务器是托管的或租用的,这样存在一个安全隐患,如果非法用户通过其他手段登上了其SQL Server服务器,或通过注入得到了存储过程,然后将存储过程中的业务逻辑等修改,如果在此前数据库未做备份那将造成不可估量的损失。对存储过程加密的示例:
create procedure sp_getAdmin
(@adminName varchar(20),
@adminPwd varchar(50))with encryption
as
select count(0)from admin where adminName=@admin-Name and adminPwd=@adminPwd
go
需要注意的是,应先备份原始的存储过程,再进行加密,同时在生产环境前需完成加密。
系统管理员密码加密是指在进行密码比对时,会通过把用户输入的密码与数据库中事先加密好的系统管理员密码进行比较,从而验证用户是否合法。下面就是ASP.NET中常用的两种Hash算法MD5和SHA1相关类[6]:
MD5相关类:
System.Security.Cryptography.MD5
System.Security.Cryptography.MD5CryptoServiceProvider()
System.Web.Security.FormsAuthentication.HashPassword-ForStoringInConfigFile(strSource,"MD5")
SHA1相关类:
System.Security.Cryptography.SHA1
System.Security.Cryptography.SHA1CryptoServiceProvider()
System.Web.Security.FormsAuthentication.HashPassword-ForStoringInConfigFile(strSource,"SHA1")
在ASP.NET类中,对于加密算法的实现过程我们无需了解,只要我们知道如何使用就可以了。以下示例是使用MD5算法对管理员密码进行Hash处理,然后向数据库的管理员表中插入密码加密后的信息记录:insert into admin values('Zhang san', upper(right(sys.fn_varBinToHexStr(hashbytes('MD5','123456')),32)))
在服务器端验证用户名和密码:///
///验证用户名与密码
///
public bool CheckUserPassword(string userName,string password)
{
SqlParameter[]paras=new SqlParameter[2];
paras[0]= new SqlParameter("adminName",user-Name);
paras[1]=new SqlParameter("adminPwd",FormsAuthentication.HashPasswordForStoringInConfigFile(password,"MD5"));
return 0 } .NET所支持的加密技术[7]分为对称密码算法和非对称密码算法。对称密码算法包含DES,RC2,Rijndael,TripleDES;非对称密码算法包括:Digital Signature Algorithm(DSA),RSA。 基于角色的安全会询问某个用户是不是处于指定角色中的问题。如果该实体处于该角色中,他就可以安全地访问一个系统资源或者应用程序特性。微软在ASP.NET 2.0发行中加入了现成的安全凭证基础结构,在凭证存储中,每个用户或角色仅限于应用程序之内。这样就允许不同应用程序使用一样的凭证存储而不会与彼此的用户名或角色相冲突。 基于角色的安全技术实施步骤[8]: (1)组织好站点中的文件; (2)利用网站管理工具进行安全配置; (3)利用控件创建安全页。 本文分析了SQL注入攻击的原理和存储过程如何防止SQL注入攻击,并且指出.NET开发中的常用安全措施,对于.NET开发初学者有很好的安全引导作用,也为下一步应用开发奠定了安全基础。4.3 基于角色的安全
5 总结