文章目录
- 一、Web应用程序与风险
- 1.1 Web应用程序的发展历程
- 1.2 Web应用程序安全
- 二、核心防御机制
- 2.1 处理用户访问
- 2.2 处理用户输入
- 2.2.1输入的多样性
- 2.2.2 输入处理方法
- 2.2.3 边界确认
- 2.2.4 多步确认与规范化
一、Web应用程序与风险
1.1 Web应用程序的发展历程
在因特网发展的早期阶段,万维网仅有Web站点构成,这些站点基本上是包含静态文档的信息库,相关信息流仅由服务器向浏览器单向传送。
如今的万维网,web上的大多数站点实际上是应用程序,在服务器和浏览器之间进行双向信息传送。
1.2 Web应用程序安全
针对web应用程序的最严重攻击,是那些能够披露敏感数据或获取对运行应用程序的后端系统的无限访问权限的攻击。
尽管web应用程序广泛使用SSL(安全套接层),且会定期进行PCI(支付卡行业)扫描,大多数web应用程序并不安全。由于应用程序无法控制客户端,用户几乎可向服务器端应用程序提交任意输入。故,SSL无法阻止攻击者向服务器提交专门设计的某个输入,应用程序使用SSL仅仅表示网络上的其他用户无法查看或修改攻击者传送的数据。
二、核心防御机制
web应用程序的基本安全问题(所有用户输入都不可信😲😲)致使应用程序实施大量安全机制来抵御攻击。web应用程序采用的防御机制在概念上都具有相似性。主要由以下几个核心因素构成:
- 处理用户访问应用程序的数据与功能,防止用户获得未授权访问;
- 处理用户对应用程序功能的输入,防止错误输入造成不良影响;
- 防范攻击者,确保应用程序在成为直接攻击目标时能够正常运转,并采取适当的防御与攻击措施挫败攻击者;
- 管理应用程序本身,帮助管理者监控其行为,配置其功能。
2.1 处理用户访问
几乎任何应用程序都必须满足一个中心安全要求,即处理用户访问其数据域功能。在通常情况下,用户一般分为匿名用户、正常通过验证的用户和管理用户。且不同的用户只能访问相应的数据。大多数web应用程序使用三层相互关联的安全机制处理用户访问:
- 身份验证
- 会话管理
- 范围控制
(1)身份验证
从理论上说,身份验证机制是应用程序处理用户访问的最基本机制。验证用户是指确定用户的真实身份。如果不采用这一机制,应用程序会将所有用户作为匿名用户来对待,这是最低一级的信任。
绝大多数的web应用程序都采用传统的身份验证模型,即要求用户提供用户名和密码。再由应用程序对其进行核实,确定其合法性。
(2)会话管理
处理用户访问的下一项逻辑任务是管理通过验证用户的会话。用户成功登录应用程序后,会访问各种页面和功能,从浏览器提出一系列HTTP请求。与此同时,应用程序还会收到各类用户(包括通过验证的用户与匿名用户)发出的无数请求。为实施有效的访问控制,应用程序需要识别并处理每一名用户提交的各种请求。
为满足以上要求,几乎所有Web应用程序都会为每一位用户建立一个会话,并向用户发布一个标识会话的令牌。
- 会话本身就是一组保存在服务器上的数据结构,用于追踪用户与应用程序的交互状态。
- 令牌是一个唯一的字符串,应用程序会将其映射到会话中。
当用户收到一个令牌后,浏览器会在随后的HTTP请求中将它返回给服务器,帮助应用程序将请求与该用户联系起来😸😸😸。如果用户在一段时间内没有发出请求,会话将会自动终止。
虽然许多应用程序使用隐藏表单字段或URL查询字符串传送会话令牌(session token),但HTTP cookie才是实现这一目的的常规方法。
少数应用程序不想用户发布会话令牌,而是通过其他方法在多个请求中重新确认用户身份。如果使用HTTP的内置身份验证机制,浏览器会自动在每个请求中重新提交用户证书。在其他情况下,应用程序会将状态信息保存在客户端而非服务器上,通常还需要对这些信息进行加密。
(3)访问控制
处理用户访问的最后一个逻辑步骤是做出并实施正确的决策,决定允许或拒绝每一个请求。应用程序可支持无数不同的用户角色,每种角色拥有特定的权限,每名用户只允许访问应用程序中的部分数据。
❗️❗️❗️访问控制机制的要求相当复杂,一般存在大量安全漏洞,使得攻击者能够非授权访问应用程序的数据与功能。
2.2 处理用户输入
所有用户输入都不可信。大量针对web应用程序的不同攻击都与提交错误输入有关,攻击者专门设计这类输入,以引发应用程序设计者无法预料的行为。输入确认是防御这些攻击的必要手段。
2.2.1输入的多样性
典型的web应用程序以各种不同的形式处理用户提交的数据。在许多情况下,应用程序会对一些特殊的输入实行非常严格的确认检查。例如,提交给登录功能的用户名的最大长度为8字符。
有些情况下,应用程序可能需要接受用户提交的任意输入。例如,一名博客应用程序用户可以建立一个主题为“攻击web应用程序”的博客。博客文章和评论可合法包含所讨论的明确攻击字符串,应用程序可能需要将这些输入保存在数据库中,写入磁盘,并以安全的方式向用户显示。不能仅仅因为输入看起来恶意(但并未显著破坏应用程序对一些用户的价值),就拒绝接受该输入。
除了用户通过浏览器界面提交的各种输入外,一个典型的应用程序还会受到大量数据,它们在服务器上生成,以便客户端能在随后的请求中将其返回给服务器。例如,cookie和隐藏表单字段。
2.2.2 输入处理方法
通常采取以下方法来处理用户输入:
1) “拒绝已知的不良输入”
这种方法一般使用一个黑名单,其中包含一组在攻击中使用的一致的字符串或模式,确认机制阻止任何与黑名单匹配的数据,并接受其他数据。
这种方法是确认用户输入效率最低的方法。通过对被阻止的输入进行调整,即可轻易避开许多基于黑名单的过滤。例如:
- 如果SELECT被阻止,则尝试SeLeCt;
- 如果or 1=1–被阻止,则尝试 or 2=2–。
在其他情况下,通过在表达式之间使用非标准字符破坏应用程序执行的令牌,可以避开旨在阻止特定关键词的过滤。如:
SELECT /foo/username,password/foo/FROM/foo/users
最后,各种基于黑名单的过滤,特别是那些由web应用程序防火墙执行的过滤,都易收到空字节的攻击。由于在托管和非托管情况下处理字符串的方式各不相同,在被阻止的表达式之前的任何位置插入空字节可能导致某些过滤器停止处理输入,并因此无法确定表达式。例如:
%00<script>alert(1)</script>
2)“接受已知的正常输入”
这种方法使用一个白名单,其中仅包含与良性输入匹配的一组字面量字符串、模式或一组标准。确认机制接受任何与白名单匹配的数据,并阻止其他数据。
在切实可行的情况下,这种方法是处理恶意输入的最有效方法,但并非解决用户输入问题的万能方法。
3)净化
以各种方式对无法保证其安全的数据进行净化,删除可能存在的恶意字符,只留下已知安全的字符,或者在进一步处理前对可能存在的恶意字符进行适当的编码或“转义”。在许多情况下,可将净化作为处理恶意输入问题的通用解决办法。
4)安全数据处理
以不安全的方法处理用户提交的数据,是许多web应用程序漏洞形成的根本原因。通常,不需要确认输入本身,只需确保处理过程绝对安全,即可避免这些漏洞。有些时候,可使用安全的编程方法避免常见问题。例如,在数据库访问过程中,正确使用参数化查询,就可以避免SQL注入攻击。
5)语法检查
在一些漏洞中,攻击者提交的输入与普通的非恶意用户调教的输入完全相同,之所以称其为恶意输入,是因为攻击者提交的动机不同。例如,攻击者可能会修改通过隐藏表单字段提交的账号,企图访问其他用户的银行账号。这时,再多的语法确认也无法区别用户与攻击者的数据。为防止未授权访问,应用程序必须确认所提交的账号属于之前提交该账号的用户。
2.2.3 边界确认
用户提交的数据不可信是造成web应用程序核心安全问题的主要原因。鉴于核心安全问题的本质,可以基于因特网(“不良”且不可信)与服务器端应用程序(“正常且可信”)之间的边界来考虑输入确认问题。
输入确认的任务就是净化到达的潜在的恶意数据,然后将“净化后”的数据提交给可信的应用程序,此后,数据即属于可信数据,不需要任何进一步的检查或者担心可能的攻击,即可进行处理。
边界确认(boundary validation)是一种更加有效的模型,此时,服务器端应用程序的每一个单独的组件或功能单元将其输入当做来自潜在恶意来源的输入对待,除客户端和服务器之间的外部边界外,应用程序在和三叔每一个信任边界上执行数据确认,每个组件都可以防御它收到的特殊类型的专门设计的输入,当数据通过不同的组件时,即可对前面转换过程中生成的任意数据值执行确认检查。而且,由于在不同的处理阶段执行不同的确认检查,它们之间不可能发生冲突。
下图说明了一种典型的情况,此时边界确认是防御恶意输入的最有效方法。在用户登录过程中,需要对用户提交的输入进行几个步骤的处理,并在每个步骤执行适当的确认检查。
- 应用程序收到用户的登录信息。表单处理程序确认每个输入仅包含合法字符,符合特殊的长度限制,并且不包含任何已知的攻击签名;
- 应用程序执行一个SQL查询检验用户证书,为防止SQL注入攻击,在执行查询前,应用程序应对用户输入中包含的可用于攻击数据库的所有字符进行转义;
- 如果用户成功登录,应用程序再将用户资料中的某些数据传送给SOAP服务,进一步获得用户账户的有关信息。为防止SOAP注入攻击,需要对用户资料中的任何XML元字符进行适当编码;
- 应用程序在用户的浏览器中显示用户的账户信息。为防止跨站点脚本攻击,应用程序对植入返回页面的任何用户提交的数据执行HTML编码。
2.2.4 多步确认与规范化
当应用程序试图通过删除或编码某些字符或表达式来净化用户输入时,攻击者可能专门设计输入,使恶意数据成功避开确认机制。例如,为防御某些跨站点脚本攻击,应用程序可能会从任何用户提交的数据中删除表达式:
<script>
但是攻击者可通过应用以下输入避开过滤器:
<scr<script>ipt>
由于过滤无法递归运行,删除被阻止的表达式后,表达式周围的数据又合并在一起,重新建立恶意表达式。
规范化是指将数据转换或编码为一个常见字符集的过程。当用户浏览器送出输入时,浏览器可对这些输入进行各种形式的编码,之所以编码,是为了能够通过HTTP安全传送不常见的字符或二进制数据,如果在实施输入过滤后才执行规范化,那么攻击者就可以通过使用编码来避开确认机制。
前端进行输入过滤,然后浏览器进行数据规范化,再通过httpp协议发送给后端。