如今的Web应用程序可能会包含危险的安全缺陷。这些应用程序的全球化部署使其很容易遭受攻击,这些攻击会发现并恶意探测各种安全漏洞。
Web环境中两个主要的风险在于:注入——也就是SQL注入,它会让黑客更改发往数据库的查询——以及跨站脚本攻击(XSS),它们也是最危险的(Category:OWASP_Top_Ten_Project)。注入攻击会利用有问题代码的应用程序来插入和执行黑客指定的命令,从而能够访问关键的数据和资源。当应用程序将用户提供的数据不加检验或编码就发送到浏览器上时,会产生XSS漏洞。
尽管2009年OWASP(Open Web Application Security Project)的一个报告表明安全方面的投资在增加(Category:OWASP_Security_Spending_Benchmarks),但是NTA Monitor的2010 Web应用安全报名表明Web的安全性跟前一年相比实际在下降。实际上,Web应用的漏洞给公司和组织带来了很多的问题。按照WhiteHat Security最新的Web站点安全性数据报告所示,被评估网站的63%是有漏洞的,每个平均有六个未解决的缺陷。(WhiteHat Website Security Statistics Report)。这些漏洞创建并维持了一个基于攻击窃取数据和资源的地下经济链。
Web应用程序需要有深度防御的措施来避免和减少安全性漏洞。1这种方式假设所有的安全预防措施都可能失败,所以安全性依赖于多层的机制从而能够覆盖其他层的失败。为了减少成功攻击的可能性,软件工程师团队必须做出必要的努力来引入适当的安全性防护措施。要达到这一点必须使用各种技术和工具来确保安全性涵盖软件产品开发生命周期的所有阶段。
软件开发生命周期中的安全性
尽管软件开发的生命周期有多种不同的划分方式,但正如图1所示,它通常包含如下的阶段:初始化、规范和设计、实现(编码)、测试、部署以及停用,这些阶段应用开发人员可以不断地重复迭代。2
尽管开发人员应该在产品的整个生命周期中都关心代码安全性,3但是他们应该特别关注三个关键阶段:1
实现。在编码过程中,软件开发人员必须使用特定应用领域内避免关键漏洞的最佳实践。这种实践的例子包括输入和输出校验、识别恶意字符以及使用参数化的命令。4 尽管这些技术在避免大多数安全漏洞方面很有效,但因为缺乏安全相关的知识,开发人员通常并不使用它们或者使用得不正确。边栏“为什么开发人员不使用安全编码实践?”更详细地讨论了这个问题。
测试。有很多技术可以在测试阶段使用,包括渗透测试(目前最流行的技术)、静态分析、动态分析以及运行时的异常检测。4 问题在于开发人员通常会关注需求功能的测试而忽略安全方面。另外,现有的自动化工具要么在漏洞探测覆盖度方面比较差要么产生太多的误报。
部署。在运行时环境中,会有不同的攻击探测机制。这些机制可以按照不同的级别运行并使用不同的探测方式。它们的使用障碍在于性能开销以及不准确的结果会打乱系统的正常行为。
开发安全的代码
为了编写没有漏洞的安全代码,4 基于Web基础设施的关键业务开发人员就要遵循编码实践,这个实践包括了深度防御的措施,它假设所有的安全性预防措施都会失败。在实现阶段依赖多层的安全机制是特别重要的,使用一个预防或保护措施来避免安全漏洞是不够的。
Web应用程序的特征在于需要三层不同的安全防线:输入校验、热点保护以及输出校验。
输入校验
大多数的安全漏洞是因为目标应用程序没有正确地校验输入数据。1所以,应用程序要考虑到所有恶意的输入直到能证明其合法,这要涵盖不可信环境中的所有数据。
输入校验是第一道防线,总体来讲就是缩小应用程序允许输入的范围,它会直接作用在用户提供的数据上。这种类型的防御要依赖输入参数在一个合法的范围内,或者如果用户提供了超出了范围的值就会停止执行。在Web应用程序中,这首先要标准化输入将其转换到基线字符集和编码。接下来,应用程序必须对标准化的输入使用过滤策略,拒绝那些值在合法范围之外的输入。这种方式能够避免很多Web应用程序中的问题,在执行输入校验时会使用正向模式匹配或正向校验。在这种情况下,开发人员建立规则来识别那些可接受的输入而不是识别有什么输入是不可接受的。尽管开发人员不能预测所有类型的攻击,但他们应该能够说明所有类型的合法输入。
关键问题在于,输入校验通常使用地并不充分,这是因为输入参数的数据域允许存在恶意数据,这是与校验执行相独立的。例如,在SQL注入漏洞中,大多数的SQL语句使用引号作为字符串分隔符,这就意味着黑客可以使用它来执行SQL注入攻击。4但是,在有些情况下,字符串输入域必须允许存在引号值,所以应用程序不能排除所有包含引号的值。
热点防护
为了应对输入校验的局限性,有必要采用第二道防线
任何类型的攻击都是以热点为目标的,热点指的就是应用程序中可能会有某种类型漏洞的代码。通用的输入校验会在应用程序中进行或者在整个Web应用程序上下文中修改输入,与之相比,第二道防线关注于保护重要的热点,例如保护那些真正使用输入域值的代码行。
一个具体的例子就是SQL注入攻击,它们大多数会使用单引号或双引号。有些编程语言提供了对这些字符的转码机制,这样它们就能用在SQL语句中了,但是只能用来在语句中分隔值。4但是这些技术有两个问题。第一,更高级的注入技术,例如联合使用引号和转义字符,可以绕过这些机制。第二,引入转义字符会增加字符串的长度,如果结果字符串的长度超过数据库限制的话,可能会导致数据截断。
正确使用参数化命令是预防注入攻击最有效的方式。1在这种情况下,开发人员定义命令的结构,并使用占位符来代表命令的变量值。稍后,当应用程序将对应的值关联到命令上时,命令解释器会正确地使用它们而不会涉及到命令的结构。
这种技术最著名的用法是数据库的预处理语句,也被称为参数化查询。4 当应用程序创建预处理语句时,语句发送到了数据库端。应用程序使用占位符来表示查询的可变部分,占位符通常会是问号或标签。随后,每次查询执行时,应用程序都要往对应的可变部分绑定值。不管数据的内容是什么,应用程序会一直使用这个表达式作为一个值而并没有SQL代码。因此,不可能修改查询的结构。
为了确保正确使用数据,很多语言允许类型绑定。但是预处理语句本身并不能修复不安全的语句——开发人员必须正确地使用它们。例如,像传统语句一样使用预处理语句——也就是使用字符串拼接来绑定SQL查询——而不是对查询的可变部分使用占位符会导致类似的漏洞。
输出校验
在将一个进程的输出发送之前进行校验能够避免用户收到他们不应该看到的信息,例如应用程序内部的异常细节,这些信息有助于发起其他的攻击。在输出校验的另一个例子当中,保护系统会搜索应用程序输出的关键信息,如信用卡号,并在发送给前端之前用星号代替。将信息编码是能够避免XSS漏洞的一种输出校验方式。4如果发送给浏览器的数据要显示在Web页面上,它应该进行HTML编码或百分号编码,这取决于它在页面的位置。通过这种方式,XSS所用的恶意字符不再具有破坏性,而且编码会保留数据的原来意义。
探测漏洞
识别安全的问题要求不仅测试应用程序的功能还要寻找代码中可能被黑客利用的隐藏的危险缺陷。5探测漏洞的两个主要方式是白盒分析和黑盒测试。
白盒分析
白盒分析需要在不执行的情况下检查代码。开发人员可以按照以下两种方式中的某一种来进行:在代码的审查或评审时以手动方式进行或者借助自动分析工具自动化进行。
代码审查(Code inspection)指的是程序员的同伴系统检查交付的代码,查找编码错误。6安全审查是减少应用程序中漏洞最有效的方式;当为关键的系统开发软件时,这是重要的过程。但是,这种审查方式通常是很费时间的、代价昂贵并需要深入了解Web的安全知识。
代码检查(Code review)是代价稍为低廉的替代方案,6它是一种简化版本的代码审查适用于分析不像前面那么重要的代码。检查也是手动进行的,但是它不需要正式的审查会议。几个专家分别进行检查,然后由主持人过滤和合并结果。尽管这是一个有效的方式,但代码检查的成本依旧是很高的。
为了减少白盒法分析的成本,开发人员有时依赖自动化工具,如静态代码分析器。静态代码分析工具会检查软件代码,要么是源码格式要么是二进制格式,并试图识别出常见的编码级别缺陷。4 使用现有工具所执行的分析会因为它们的复杂性而有所不同,这种差异体现在考虑单条语句和命令或考虑代码行之间的依赖。除了模型检查和数据流分析等功能之外,这些工具还会自动关注可能的编码错误。它的主要问题在于细致的分析是很困难并且因为源码的复杂性和缺乏动态(运行时)的视角有很多安全缺陷很难被发现。
尽管使用静态代码分析工具很重要,但是它有时会降低开发人员的生产效率,这主要是因为误报,这会导致没有用处的额外工作。7为了避免这种情况,除了要有足够的时间学习怎样使用这些工具以外,开发人员需要一些策略来保证正确使用这些工具。例如,有必要指定规则来分类和选择开发人员应该处理的警告信息。同时,开发人员还要配置分析工具只报告那些与当前开发上下文相关的警告。没有接受怎样使用静态分析训练的开发人员最终会低估它的真正效益并且通常不能发挥它的所有功能。
黑盒测试
黑盒测试指的是从外部的视角分析程序的执行。简而言之,它会比较软件执行的输出与期望的结果。5 对于软件的检验和确认来说,测试可能是最常用的技术了。
对于黑盒测试来讲,有多种级别,从单元测试到集成测试再到系统测试。测试方式可以是正式的(基于模型和定义良好的测试规范)也可以不那么正式(被称为“冒烟测试”,一种粗糙的测试目的是快速暴露简单的缺陷)。
健壮性是黑盒测试一种特殊形式,它的目标是查看系统在错误输入条件下的行为。渗透测试是特殊类型的健壮性测试,它会分析在遇到恶意输入时的代码执行并查找潜在的漏洞。在这种方式中,测试人员使用模糊技术,这包含通过HTTP请求,提交意料之外的或非法的数据项到Web应用程序上并检查它的响应。4测试人员不需要了解实现细节——他们在用户的角度来测试应用程序的输入。对于每种漏洞类型,可能会有上百次甚至上千次的测试。
渗透测试工具会自动搜索漏洞,这避免了手工为每种类型的漏洞构建上百个甚至上千个测试所带来的重复和乏味的工作。Web应用的常见自动化安全测试工具一般会称为Web应用或Web安全扫描器。这些扫描器可以很容易地测试应用程序以发现漏洞。对于目标应用,它们会有一些预定义的测试用例,所以用户只需要配置一下扫描器并让它测试应用即可。一旦扫描器完成测试,它会报告所探测到的漏洞。大多数的扫描器都是商业产品,尽管也有免费的应用程序扫描器,但是与商用版本相比,它们缺少大多数的功能所以用的很有限。