Header Manipulation
Abstract
HTTP 响应头文件中包含未验证的数据会引发 cache-poisoning、 cross-site scripting、 cross-user defacement、 page hijacking、 cookie manipulation 或 open redirect。
Explanation
以下情况中会出现 Header Manipulation 漏洞:
- 数据通过一个不可信赖的数据源进入 Web 应用程序,最常见的是 HTTP 请求。
- 数据包含在一个 HTTP 响应头文件里,未经验证就发送给了 Web 用户。 如同许多软件安全漏洞一样, Header Manipulation 只是通向终端的一个途径,它本身并不是终端。 从本质上看,这些漏洞是显而易见的: 一个攻击者将恶意数据传送到易受攻击的应用程序,且该应用程序将数据包含在 HTTP 响应头文件中。 其中最常见的一种 Header Manipulation 攻击是 HTTP Response Splitting。 为了成功地实施HTTP Response Splitting 盗取,应用程序必须允许将那些包含 CR(回车,由 %0d 或
指定)和 LF(换行, 由 %0a 或
指定)的字符输入到头文件中。 攻击者利用这些字符不仅可以控制应用程序要发送的响应剩余头文件和正文,还可以创建完全受其控制的其他响应。 如今的许多现代应用程序服务器可以防止 HTTP头文件感染恶意字符。 例如,如果尝试使用被禁用的字符设置头文件,最新版本的 Apache Tomcat 会抛出IllegalArgumentException。 如果您的应用程序服务器能够防止设置带有换行符的头文件,则其具备对 HTTP Response Splitting 的防御能力。 然而,单纯地过滤换行符可能无法保证应用程序不受 CookieManipulation 或 Open Redirects 的攻击,因此必须在设置带有用户输入的 HTTP 头文件时采取措施。
例: 下列代码片段会从 HTTP 请求中读取网络日志项的作者名字 author,并将其置于一个 HTTP 响应的 cookie 头文件中。
String author = request.getParameter(AUTHOR_PARAM);
...
Cookie cookie = new Cookie("author", author);
cookie.setMaxAge(cookieExpiration);
response.addCookie(cookie);
假设在请求中提交了一个字符串,该字符串由标准的字母数字字符组成,如 "Jane Smith",那么包含该cookie 的 HTTP 响应可能表现为以下形式:
HTTP/1.1 200 OK
...
Set-Cookie: author=Jane Smith
...
然而,因为 cookie 值来源于未经校验的用户输入,所以仅当提交给 AUTHOR_PARAM 的值不包含任何 CR 和LF 字符时,响应才会保留这种形式。 如果攻击者提交的是一个恶意字符串,比如
"Wiley Hacker
HTTP/
1.1 200 OK
..."
,那么 HTTP 响应就会被分割成以下形式的两个响应:
HTTP/1.1 200 OK
...
Set-Cookie: author=Wiley Hacker
HTTP/1.1 200 OK
...
显然,第二个响应已完全由攻击者控制,攻击者可以用所需的头文件和正文内容构建该响应。 攻击者可以构建任意 HTTP 响应,从而发起多种形式的攻击,包括: cross-user defacement、网络和浏览器 cache poisoning、 cross-site scripting 和 page hijacking。 cross-user defacement: 攻击者可以向一个易受攻击的服务器发出一个请求,导致服务器创建两个响应,其中第二个响应可能会被曲解为对其他请求的响应,而这一请求很可能是与服务器共享相同 TCP 连接的另一用户发出的。 这种攻击可以通过以下方式实现:攻击者诱骗用户,让他们自己提交恶意请求;或在远程情况下,攻击者与用户共享同一个连接到服务器(如共享代理服务器)的 TCP 连接。 最理想的情况是,攻击者只能通过这种做法让用户相信自己的应用程序已经遭受了黑客攻击,进而对应用程序的安全性失去信心。 最糟糕的情况是,攻击者可能提供经特殊技术处理的内容,这些内容旨在模仿应用程序的执行方式,但会重定向用户的私人信息(如帐号和密码),将这些信息发送给攻击者。 cache-poisoning: 如果多用户 Web 缓存或者单用户浏览器缓存将恶意构建的响应缓存起来,该响应的破坏力会更大。 如果响应缓存在共享的 Web 缓存(如在代理服务器中常见的缓存)中,那么使用该缓存的所有用户都会不断收到恶意内容,直到清除该缓存项为止。 同样,如果响应缓存在单个用户的浏览器中, 那么在清除该缓存项以前,该用户会不断收到恶意内容。然而,影响仅局限于本地浏览器的用户。
Cross-Site Scripting:
一旦攻击者控制了应用程序传送的响应,就可以选择多种恶意内容来传播给用户。Cross-Site Scripting 是最常见的攻击形式,这种攻击在响应中包含了恶意的 JavaScript 或其他代码,并在用
户的浏览器中执行。 基于 XSS 的攻击手段花样百出,几乎是无穷无尽的,但通常它们都会包含传输给攻击者的私人数据(如 Cookie 或者其他会话信息)。在攻击者的控制下,指引受害者进入恶意的网络内容;或者利用易受攻击的站点,对用户的机器进行其他恶意操作。 对于易受攻击的应用程序用户,最常见且最危险的攻击就是使用 JavaScript 将会话和 authentication 信息返回给攻击者,而后攻击者就可以完全控制受害者的帐号了。
Page Hijacking:
除了利用一个易受攻击的应用程序向用户传输恶意内容,还可以利用相同的根漏洞, 将服务器生成的供用户使用的敏感内容重定向,转而供攻击者使用。 攻击者通过提交一个会导致两个响
应的请求,即服务器做出的预期响应和攻击者创建的响应,致使某个中间节点(如共享的代理服务器)误导服务器所生成的响应,将本来应传送给用户的响应错误地传给攻击者。 因为攻击者创建的请求产生了两个响应, 第一个被解析为针对攻击者请求做出的响应,第二个则被忽略。 当用户通过同一 TCP 连接发出合法请求时, 攻击者的请求已经在此处等候,并被解析为针对受害者这一请求的响应。 这时,攻击者将第二个请求发送给服务器,代理服务器利用针对受害者(用户)的、由该服务器产生的这一请求对服务器做出响应,因此, 针对受害者的这一响应中会包含所有头文件或正文中的敏感信息。
Cookie Manipulation:
当与类似Cross-Site Request Forgery 的攻击相结合时,攻击者就可以篡改、添加、甚至覆盖合法用户的 cookie。
Open Redirect:
如果允许未验证的输入来控制重定向机制所使用的 URL,可能会有利于攻击者发动钓鱼攻击。
Recommendation
针对 Header Manipulation 的解决方法是,确保在适当位置进行输入验证并检验其属性是否正确。 由于Header Manipulation 漏洞出现在应用程序的输出中包含恶意数据时,因此,合乎逻辑的做法是在应用程序输出数据前一刻对其进行验证。 然而,由于 Web 应用程序常常会包含复杂而难以理解的代码,用以生成动态响应,因此,这一方法容易产生遗漏错误(遗漏验证)。 降低这一风险的有效途径是对 Header Manipulation 也执行输入验证。 由于 Web 应用程序必须验证输入信息以避免出现其他漏洞(如 SQLInjection),因此,一种相对简单的解决方法是扩充应用程序现有的输入验证机制,增加针对 HeaderManipulation 的检查。 尽管具有一定的价值,但 Header Manipulation 输入验证并不能取代严格的输出验证。 应用程序可能通过共享的数据存储或其他可信赖的数据源接受输入,而该数据存储所接受的输入源可能并未执行适当的输入验证。 因此,应用程序不能间接地依赖于该数据或其他任意数据的安全性。 这就意味着, 避免 Header Manipulation 漏洞的最佳方法是验证所有应用程序输入数据或向用户输出的数据。 针对Header Manipulation 漏洞进行验证最安全的方式是创建一份安全字符白名单,其中的字符允许出现在 HTTP响应头文件中,并且只接受完全由这些受认可的字符组成的输入。 例如,有效的用户名可能仅包含字母数字字符,帐号可能仅包含 0-9 的数字。 更灵活的解决方法称为黑名单方法,但其安全性较差,这种方法在进行输入之前就有选择地拒绝或避免了潜在的危险字符。 为了创建这样的列表,首先需要了解在 HTTP 响应头文件中具有特殊含义的一组字符。 尽管 CR 和 LF 字符是 HTTP Response Splitting 攻击的核心,但其他字符,如 ":" (冒号)和 "="(等号),在响应头文件中同样具有特殊的含义。 一旦在应用程序中确定了针对Header Manipulation 攻击执行验证的正确点,以及验证过程中要考虑的特殊字符,下一个难题就是确定在验证过程中该如何处理各种特殊字符。 应用程序应拒绝任何要添加到 HTTP 响应头文件中的包含特殊字符的输入, 这些特殊字符(特别是 CR 和 LF)是无效字符。 许多应用程序服务器都试图避免应用程序出现 HTTP
Response Splitting 漏洞,其做法是为负责设置 HTTP 头文件和 cookie 的函数提供各种执行方式,以检验是否存在进行 HTTP Response Splitting 攻击必需的字符。 不要依赖运行应用程序的服务器,以此确保该应用程序的安全。 开发了某个应用程序后,并不能保证在其生命周期中它会在哪些应用程序服务器中运行。 由于标准和已知盗取方式的演变,我们不能保证应用程序服务器也会保持同步。