摘 要: SQL( Structured Query Language) 注入是一种常用且易于实施的攻击手段,对 Web 应用程序的安全构成严重危害. 通过分析 SQL 注入攻击的原理,提出一种基于程序分析技术的 SQL 注入防御原型系统. 该系统以静态分析为基础,对污染数据进行跟踪,并为包含污染数据的 SQL 语句建立合法查询自动机模型,然后以此作为被测程序的探针,进行动态测试,跟踪并记录程序的执行情况. 系统的实现针对 Java 的 Web 应用程序,不需要修改服务器以及数据库平台的配置. 实验表明,该系统具有较好的防范 SQL 注入的效果和较低的运行开销.
关 键 词: Web 安全; SQL 注入; 静态分析; 动态分析
1 引 言
随着网络产业的迅猛发展,基于 B/S 模式的 Web 应用程序越来越普及,该模式包括数据库服务器、应用服务器与客户端三级. 许多程序员在编写 Web 应用时只注重功能的实现,没有对用户输入数据的合法性进行有效判断,使应用程序存在安全隐患. SQL 注入攻击是当今最危险、最普遍的基于Web 的攻击之一. 所谓 SQL 注入攻击,就是攻击者通过提交精心构造的数据库查询代码,欺骗服务器执行恶意的 SQL 命令,以获取用户密码等敏感信息,进而获取主机控制权限等.统计表明,在互联网上的 Web 服务器遭受的各类应用层攻击中,SQL 注入占有极大的比例.
针对上述问题,许多研究人员关于如何正确检测和防范SQL 注入攻击做了大量工作. 其中文献[1]提出一种基于SQL 语法预分析的策略,该策略抽象出各类注入的语法结构,然后将用户输入预先组装成完整的 SQL 语句,对该语句进行语法分析,如果发现具有 SQL 注入特征的语法结构,则判定为 SQL 注入攻击. 文献[2]提出一种基于指令集随机化技术的 SQL 注入防范系统来判定是否存在攻击. 这种方法的缺点是在随机化密钥泄露的情况下,攻击者很容易进行 SQL注入攻击,而且部署比较困难. 文献[3]的核心思想是通过学习期的训练,为 Web 应用程序自动建立各参数的异常使用模型,在此后的检测过程中依据此模型来判断实际网络中的各种行为是否异常. 这种方法的优势在于能够不受限制的发现各种异常行为. 由于需要一个学习期间,在此期间需要一个非常"干净"的数据来训练,否则容易产生漏报. 而且一旦内部的业务模型发生了变化,这个学习过程又需要重新进行.根据目前流行的防范技术分析得知,几乎所有对付 SQL注入攻击的方法都是基于静态分析来进行判断的. 该模型一个主要的缺陷就是不能正确评估用户输入结构,导致许多新型的攻击可以成功绕过认证达到攻击的目的,所以本文在研究相关工作的基础上,提出了一套基于程序分析的动态SQL注入防御模型.
2 基于程序分析技术的 SQL 注入防御系统
2. 1 程序分析技术理论
程序分析技术分为静态分析和动态分析两种. 静态分析[4]的主要特征是不需要执行所测试的程序,对程序的数据流和控制流等静态结构进行分析,在程序运行前尽可能多的发现其中隐含的错误,从而检测出软件中的安全漏洞. 和其他程序分析方法相比,该方法具有自动化程度高和分析速度快的优点. 但这种技术对于 Web 应用来说是失败的,因为该技术没有充分考虑 Web 应用运行时的行为特征; 动态分析[5]通过运行程序,来获得程序在某次执行过程中的真实情况,将程序的输入、输出和程序行为紧密地联系起来,因而能观察Web 应用的不同对象之间是如何交互的. 动态分析的不足之处在于仅仅依靠一次或多次的程序执行情况有可能无法发现软件的安全漏洞. 软件结构和行为之间的强烈依赖关系,决定了静态分析和动态分析相结合能达到更好的分析效果. 本文在研究了程序分析技术的基础上,针对静态和动态优缺点的互补性,提出了一种聚合静态分析和动态分析的 SQL 注入防御模型.
2. 2 防御系统结构
防御系统主要由标识模块、静态分析模块和动态分析模块[6]三部分组成. 各模块之间进行必要的数据交换和通信,最后将软件的安全漏洞报告给分析人员. 系统结构如图1 所示:2. 2. 1 标识模块如果在 Web 应用程序 SQL 注入漏洞检测中发现了类似数据库查询这样的语句,并不能等同于这就是一个安全漏洞,必须是查询语句中包含了用户输入数据. 因此对存储在服务器端预执行数据库查询语句进行分析前,首先对每个用户输入的部分进行标注,则动态分析的范围可以缩减到只有标识的用户语句. 如图 2 所示的关系结构图( 图中 I 为用户输入、E为执行语句、C 为语句与用户输入连接关系、P 为语句之间的串联关系) ,假设在分析数据库查询语句时只有 E1、E2、E3 这三个语句与用户输入有关,那么在动态运行时只需要检查被标记的语句即可,节省很多有效的判断时间.
2. 2. 2 静态分析模块
静态分析模块对原始程序进行抽象建立程序的中间表示形式. 作为一种良好的中间表示,抽象语法树不仅能适应 Java语言的语法结构,而且它还能达到对源程序进行一个预处理的目的. 首先词法分析器对源程从左至右逐个字符进行扫描,产生一个个的单词符号,包括: 关键字,标识符,常数运算符,界符等,然后语法分析器针对非左递归文法采用递归 下降分析方法,将读取的单词符号组合起来进行语法规则匹配,建立一棵与分析程序相匹配的语法分析树. 根据有穷状态自动机原理在标注点生成合法状态模型. 通过跟踪程序执行过程中变量、存储单元、寄存器的值,达到跟踪攻击路径,获取漏洞信息的目的.
2. 2. 3 动态分析模块
在动态分析时,以自动机模型作为探针插装到被测程序.通过 Web 程序在真实环境下的执行过程,向被测程序中插入合法查询语句的自动机模型. 动态监测程序运行过程中动态生成的 SQL 语句和相应污染数据入口点模型,根据它们的匹配情况来发现安全漏洞. 如果 SQL 语句能够达到终结状态则说明该语句是正常的,否则报告发生了 SQL 注入攻击.
3 关键技术的实现
本原型系统的实现有三个关键技术: 标识模块包括数据流的跟踪模式,静态分析模块包括状态集模型的生成,动态分析模块包括程序的插装技术.
3. 1 数据流跟踪
在 Java 程序中所有用户数据都会封装成 String 类或StringBuffer 类的对象,然后通过一些方法的调用在程序中不断转化,因此所有包含了用户输入数据的 String 类或 String-Buffer 类的对象都被认为是污染数据. 数据流跟踪技术[7]为污染数据对象添加一个布尔型的属性字段 tainted( 初始值设置为 true,表示从这里获取的代写论文数据可能会引起程序的安全问题) ,在程序执行过程中跟踪对象 tainted 属性的传播,当一个tainted 属性字段值为 true 的对象作为实参传入了接收方法时,一个 SQL 注入攻击的安全问题就可能发生. 例如以下原始 string 类:public class string{ResultSet rs = stmt. execute( queryString) ;return rs;}为 string 类添加 boolean 类型字段:void addBoolField( Class class,String name){class. addField( name) ;}其中 addBoolField 是添加字段的方法,方法的第一个参数class 表示要进行字段添加的类,name 参数表示要添加的字段名称. 这里传入参数 string 和 tainted,完成字段的添加.接下来在类的方法体中加入判断性语句,并在获知 string对应实参的 tainted 字段为 true 情况下,把方法返回对象的tainted 字段也设置成 true. 本文的设计是在原始方法体上封装 if-else 语句,方法体如下:private static void checkedTainted( Class class,String name) {List list = class. getDeclaredMethod( name) ;/ / 获得方法信息String nname = name + " $ rename" ;/ / 重命名旧方法list. setName( nname) ;StringBuffer body = new StringBuffer( ) ;/ / 添加判断代码Class returnType = list. getReturnType( ) ;/ / 获得方法返回类型body. append( " { \ n" ) ;/ / 修改方法体body. append( returnType. getName( ) +" result = new " + returnType. getName( ) + " ( ) ; \ n" ) ;body. append( " \ nif( class. tainted = = true) { \ n \ tresult = "+ nname + " ; \ n \ tresult. tainted = true; \ n" ) ;body. append( " \ tSystem. out. println(\ " tainted is true! \ " ) ; \ n" ) ;body. append( " } else{ \ n \ tresult = " + nname + " ; \ n" ) ;body. append( " \ tSystem. out. println(\ " tainted is false! \ " ) ; \ n" ) ;body. append( " } \ n \ treturn rusult; \ n} \ n" ) ;Class. setBody( body. toString( ) ) ;/ / 将方法添加进声明的类class. addMethod( Class) ;System. out. println( body. toString( ) ) ;/ / 显示添加的方法体
为了检测到更多的安全漏洞,除了跟踪显而易见的污染数据外,还需要跟踪由污染数据转化而来的,隐藏在程序的变量或对象中的污染数据. 通过对污染数据做标记,动态跟踪程序运行过程中污染数据的传播路径. 当检测到一个攻击时,数据流跟踪技术提供详细的攻击过程,给出由于污染数据所导致的漏洞被利用的过程. 通过跟踪污染数据的输入,记录数据的流向,分析得到 SQL 注入攻击漏洞,降低了漏报率.
3. 2 自动机模型
自动机模型的生成使用 JSA[8]( Java String Analyzer) 库函数实现. JSA 是由美国学者 A. S. Christensen,A. Mller 和M . I. Schw artzbach 推出的静态分析工具,已经被许多研究人员成功使用,可以方便的分析 Java 程序中的字符串操作的流程图. JSA 采用有穷状态自动机原理[9],对输入进行读入,根据读入进行状态转移,从而分析出 Java 程序中字符串表达式所有值的模型. 例如以下程序段[10]:for ( i = 0; i < n; i + + )x = " 0" + x + " 1" ;out. println x. replaceAll( " 00" ," 0" ) ;其中 x. replaceAll( "00","0") 的作用是把字符串 x 中的"00"字符串替换成"0",此语句可以用下面的有限状态自动机来表示:
其中 A 表示非零的所有字符. 在这个状态机中有三个状态,"0"表示初始状态,"0"和"2"表示终结状态,"0/e"和"A /0A" 分别表示在输入字符为" 0" 和" A" 时,输出为" e" 和"0A" . 如果输入字符串" 00ab11" ,则输出为" 0ab11" . 设初始状态为 S,x 的值为"abc"或"xyz",n 的值为整型,则此状态机对应的上下文无关文法如下所示:S→abc | xyz | X1X→0abc | 0xyz | 0S1因此整个文法所表示的字符串表达式的值为:{ 0nabc12n| n≥0} ∪{ 0nxyz12n| n≥0} ∪{ 0n + 1abc12n + 1| n≥0} ∪{ 0n + 1xyz12n + 1| n≥0}为了有效防止攻击者的猜解,避免其构造相同的状态图,在词法分析识别 SQL 语言关键字的基础上,对合法状态集关键字进行随机化处理,例如对于如下语句: " select info fromusers w here login = '" + login + " ' and pin = '" + pin + " '" ,其所有可能值为两个字符串型值,假设密钥是"12",随机化后的 SQL 语句对应的自动机模型如图 4 所示( 其中'var'代表用户输入的变量,粗圆代表终结状态) :
而如果输入 login←' or 1 =1--,pin←''时,形成的 SQL 语句的值为永真式,如下页图 5 所示.该语句生成的模型不满足合法查询的自动机模型,我们就认为这条语句为恶意攻击,并且因为有了随机化处理而使攻击者无法构造相同的状态机,进一步降低了漏报率.3. 3 程序插装为了进行数据流跟踪,需要对源程序进行插装. 程序插装[11]是为了收集程序的运行时信息而在程序的注入点插入探针,以达到揭示程序内部行为和特性的目的. 其中探针是指嵌在被测源程序中一条或多条测试语句,用以完成动态测试图 5 恶意 SQL 查询模型Fig. 5 Query model of malicious SQL信息的记录,同时保持被测程序的逻辑完整性. 程序插装是用来查找静态分析不能找到或不易找的错误的主要动态分析技术. 由于本原型系统采用的开发语言 Java 是面向对象的语言,因此在设计动态方法对 SQL 漏洞进行验证时,我们采用了定义插装类的方法. 对源程序进行静态分析时生成的自动机模型就是程序插装的探针. 如下所示:try{sql = " select info from users w here login= '" + login + " ' and pin = '" + pin + " '" ;monitor. report( s,automata model) ;resultset rs = stat. executequery( s) ;}catch ( exception e) { }其中 sql 表示数据库查询语句,automata model 为该注入点的自动机模型. 如果查询语句与模型规则匹配的时候出错,则抛出异常,并结合当前的出错点和欲匹配的规则提示出错位置和错误信息,提前结束程序的执行.
4 原型系统分析与评估
本文实现的防 SQL 注入原型系统的评估通常考虑两点:功能分析衡量误报率和漏报率; 性能分析衡量实时性. 误报是将正常输入判定为SQL注入,漏报则是将SQL注入判定为正常输入. 我们从 GotoCode 网页 ( http: / /www. gotocode.com) 下载了 5 个 Web 应用程序( forum、ledger、regform、task-man、yellow page) 作为测试对象,实现最基本的用户注册,登录,维护以及管理功能等等,程序不作任何用户输入信息检验,数据库查询操作( 包括合法的查询请求和恶意的查询请求) 尽量涵盖实际 Web 应用程序中存在的大量有代表性的漏洞,便于实施 SQL 注入攻击. ( 软硬件平台: Pentium 2. 4G/256M / Fedora 4; Web 服务器: Apache Tomcat5 + Java1. 5 +MySQL4. 1) . 表 1,表 2 分别是静态分析和动态分析得到的相关数据,其中" 自动机大小" 表示生成自动机的平均节点数( 括号内的数据分别表示自动机的最少和最多节点数) ," 时间"分别表示加载类,建立自动机和插装探针的时间.
以上实验数据为独立测试 20 次的平均值. 从表 1 可以看出应用程序采用 JSA 技术防御 SQL 注入攻击,只在服务器端消耗一定时间建立自动机模型; 从表 2 可以得出以下结论: 本原型系统具有较好的防范 SQL 注入的效果,并且在系统对页面响应时间的影响方面只增加了 0. 16s 左右的客户端等待时间,这完全在用户可以接受的范围之内.通过污染数据流的跟踪,可以减少 SQL 注入漏洞的漏报率,同时借助程序插装技术能有效的降低误报率. 但是由于对语义的理解、别名信息的判断、静态分析算法都是不完备的近似算法,导致精确的判断污染数据在动态执行时指向的对象以及跟踪污染数据流的轨迹是一个不可判定问题[12],所以静态分析往往要在分析的能力和精度上进行权衡. 并且静态分析的本质是建立程序的状态模型,然后分析程序是如何在这些状态之间转换,但当目标系统的规模到一定程度时,静态分析要对所有状态进行分析就不可行了,于是以此为基础的动态分析性能将降低,会导致误报和漏报的产生.
5 结 论
本文提出的基于程序分析技术防御 SQL 注入攻击的新方法,通过污染数据流跟踪技术在应用程序注入点建立自动机模型,运用监控技术于 SQL 注入攻击的防御策略,依据程序运行时动态分析包含污染数据流的 SQL 语句是否满足自动机模型来判定是否发生了 SQL 注入攻击,并以此策略为基础建立了原型系统. 系统的实现针对基于 Java 的 Web 应用程序,不依赖于任何数据库或服务器平台,易于移植. 从表 1,表2 中可以看出本文提出的原型系统运行开销较低,防御 SQL注入攻击的效果明显. 本文提出的方法需要能够获得 Web 应用程序源代码,并且需要修改源代码,如何在有效防御 SQL注入攻击的前提下,无需改变源代码进行程序的插装,是我们今后研究的重点,同时由于聚合静态分析和动态分析的方法仍然是两种方法单独进行,都需要消耗一定的时间,所以寻找更加有效的结合,使得它们成为一个统一的整体也是我们努力的方向.
References:
[1] Zhou Jing-li,Wang Xiao-feng,Yu Sheng-sheng,et al. A newpolicy to defend against SQL injection attacks[J]. Computer Sci-ence,2006,33( 11) : 64-68.
[2]Stephen W Boyd,Angelos D Keromytis. SQLrand: preventing SQLinjection attacks[C]. Proceedings of the 2nd Applied Cryptographyand Network Security ( ACNS) Conference,Berlin: Springer BerlinHeidelberg,2004,292-302.
[3]Valeur F,Mutz D,Vigna G. A learning-based approach to the de-tection of SQL attacks[C]. Proceedings of the Conference on De-tection of Intrusions and Malware and Vulnerability Assessment( DIMVA) . Berlin: Springer Heidelberg,2005,123-140.
[4]Fu X,Lu X,Peltsverger B,et al. A static analysis framework fordetecting SQL injection vulnerabilities[A]. Proceedings of the 31stAnnual International Computer Software and Applications Confer-ence[C],New York: ACM ,2007,87-96.
[5]Cheng Win-nie,Qin Zhao,Bei Yu,et al. Taint trace: efficientflow tracing with dynamic binary rewriting[C]. Proceedings of the11th IEEEE Symposium on Computers and Communications( ISCC'06) ,NJ: IEEE,2006,749-754.
[6] William G J Halfond,Alessandro Orso. AMNESIA: analysis andmonitoring for neutralizing SQL-injection attacks[C]. Proceedingsof the 20th IEEE / ACM International Conference on AutomatedSoftware Engineering,ACM ,2005,174-183.[7]Huang J C. Program instrumentation and software testing[C].IEEE Computer. USA: IEEE Computer Society,1978,25-32.
[8]Christensen A S,Mller A,Schwartzbach M I. Precise analysis ofstring expressions[C]. Proceedings of the 10th International Static A-nalysis Symposium,Berlin: Springer Berlin Heidelberg,2003,1-18.
[9]Harry R Lewis,Christos H Papadimitriou. Elements of the theoryof computation ( second edition) [M]. Beijing: Prentice Hall,2002,34-37.
[10]Yasuhiko Minamide. Static approximation of dynamically genera-ted web pages[A]. Proceedings of the 14th International Confer-ence on World Wide Web[C],New York: ACM ,2005,432-441.
[11]Halfond W,Orso A,Manolios P. WASP: protecting web applica-tions using positive tainting and syntax-aware evaluation[C]. Pro-ceedings of the IEEE Transactions on Software Engineering,NJ:IEEE,2008,65-81.
[12]Landi W. Undecidability of static analysis[J]. ACM Lett. Pro-gram. Lang. Syst,New York: ACM ,1992,4( 1) : 323-337.