这是一年前写的项目笔记,一直在我的待办事项里等待做总结,今天偶然翻到,就整理成文章发出来。 谨以此文怀念 乌云

201705/wooyun.jpg


事情缘由

春节前的某一天,收到一封来自乌云(国内知名白帽子团队)的邮件, 告知我厂网站上出现一例 XSS 漏洞。 因为以前对 XSS 输入做过防御,还以为是某个前端 DOM 上的 XSS 漏洞, 后来仔细一看,不妙,是个影响甚大的存储型 XSS 漏洞。

这里简单科普一下 XSS 跨网站脚本 -维基百科,自由的百科全书 中介绍到:

跨网站脚本(Cross-site scripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。 它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。

XSS 攻击可以分成两种,反射性 XSS / 存储型 XSS。前者是需要用户触发的 XSS, 针对当前用户的攻击行为。而后者存储型 XSS 则更为严重,一旦攻击代码被保存, 所有访问被攻击的页面,都会触发用户被攻击行为。

这次爆出的问题就是最严重的存储型 XSS,意味着每个访问到有问题页面的用户都会中招。 时间紧迫,问题必须被解决。

XSS 实现手段

在解决问题之前,需要对这个问题有必要的基础认识。 我们先看看 XSS 攻击是如何工作的,以及攻击者的目的是什么。

XSS 的原理是通过构造特殊的数据,并通过传递参数或者保存表单数据的方式, 让这些构建的数据破坏 DOM 结构,从而让自己预先构造数据中的 JS 脚本被执行。

检查存储型 XSS 漏洞的方法,可以在对应的 input field 里放入一些构造的数据,如果保存后可以被执行,就说明存在 XSS 漏洞。

常见的检测方法(来自 跨网站脚本 - 维基百科,自由的百科全书

><script>alert(document.cookie)</script>
='><script>alert(document.cookie)</script>
"><script>alert(document.cookie)</script>
<script>alert(document.cookie)</script>
<script>alert (vulnerable)</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
<script>alert('XSS')</script>
<img src="javascript:alert('XSS')">
<img src="http://xxx.com/yyy.png" onerror="alert('XSS')">
(这个仅限IE有效)

攻击者通过 XSS 可以窃取用户的相关信息,如果用户是管理员,那么影响更大。 通过这些身份信息,攻击者可以进一步篡改信息或者进行诈骗,后果不堪设想。 PS:一个有效粗暴的方式,是将对公、对内系统的域名分离,对内部系统进行物理级别隔离。

我厂历史上的处理方案

XSS 问题又来已久,咱厂子开了这么久,历史上如何防御的呢? 答案是用了两个策略:第一个是使用 OWASP 提供的库进行内容过滤,第二个是在存储数据时,存储了转义后的数据。

在技术上处理 XSS,有两种态度可以选择:第一种是前置过滤,即将用户所有数据都进行转义, 在输出时候在前端(模板渲染)层面直接输出。 第二种是用户输入的数据不经过转义就直接存储起来,前端在使用时候保证对数据进行转义。

我厂历史上使用的方案的前者,优点是在于前端不需要在每个地方转义, 避免某个地方忘记了转义,从而导致漏洞。缺点则是在输出内容到非 Web 客户端时候,比如 APP,需要进行额外的数据处理过程, 否则 HTMLEncode 的内容,在 APP 上面无法正确输出。

这个处理方案是稳妥的,那么为什么最近又暴露出问题了? 排查之后发现,原来最近有若干个服务迁移到了一个新系统, 而新系统在安全上面没有全局处理,所以爆出了漏洞。

本次处理方案

知道了原因,那么可以快速解决问题了。在这次处理过程中,我们讨论了在当前移动平台增长迅速,Web 平台增长缓慢的大势下,能否直接存储用户原始数据? 而且由于规范制定不严格,目前系统内有些地方存储转码后数据,有些地方存储转码前数据。 导致在一些特殊的字符(颜文字)处理上不一致,从而导致在处理 br / < 这类特殊字符时,表现不同。

由于 DB 中有部分数据转义处理,部分数据原文存储,所以先处理输出后敏感信息,在模板层面启用全局 encode。 将有危险的数据转移为在 HTML 文本。

PS:现代 Web 框架的模板渲染引擎,一般会默认开启 HTMLEncode,而 Freemarker 居然在 2.3.24-rc01 才支持,现在都没有发布,唉……

处理方案:

  • 开启全局 HTML 输出 Encode,有一个 Default HTML-escape using Freemarker 方案,可以默认开启 Html Encode,在这个处理方案中,需要注意有些地方真的需要输出原始 html,需要 noescape 特殊处理
  • 检查所有前端操作,禁止字符串拼接,使用框架支持的模板进行渲染,拖小菊的福,新系统在这块工作完成度一直比较好
  • 将 OWASP 方案强制开启

其他 Tips

OWASP 有一个很长的 列表,教导如何避免 XSS,里面提到了:

  • 为何以及如何进行「积极防御」,对立面是仅仅输出时候转义内容本身
  • 几条对抗 XSS 的规则
    • 尽量不在特定地方输出不可信变量:script / comment / attribute / tag / style, 因为逃脱 HTMl 规则的字符串太多了。
    • 将不可信变量输出到 div / body / attribute / javascript tag / style 之前,对 & < > " ' / 进行转义
    • 将不可信变量输出 URL 参数之前,进行 URLEncode
    • 使用合适的 HTML 过滤库进行过滤
    • 预防 DOM-based XSS,见 DOM based XSS Prevention Cheat Sheet
    • 开启 HTTPOnly cookie,让浏览器接触不到 cookie

最后送上一个 XSS 攻击工具 http://webxss.net/,知己知彼,百战不殆。


原文链接: XSS 攻击的处理 | Log4D

3a1ff193cee606bd1e2ea554a16353ee

欢迎关注我的微信公众号:窥豹

窥豹