对于链接跳转,如 或location.href="xxx",要检验其内容,禁止以javascript:` 开头的链接,和其他非法的 scheme。
根据上下文采用不同的转义规则
某天,小明为了加快网页的加载速度,把一个数据通过 JSON 的方式内联到 HTML 中:
<script>var initData = <%= data.toJSON() %>
</script>
插入 JSON 的地方不能使用 escapeHTML(),因为转义 " 后,JSON 格式会被破坏。
但安全组又发现有漏洞,原来这样内联 JSON 也是不安全的:
当 JSON 中包含 U+2028 或 U+2029 这两个字符时,不能作为 JavaScript 的字面量使用,否则会抛出语法错误。
当 JSON 中包含字符串 时,当前的 script 标签将会被闭合,后面的字符串内容浏览器会按照 HTML 进行解析;通过增加下一个 标签等方法就可以完成注入。
于是我们又要实现一个 escapeEmbedJSON() 函数,对内联 JSON 进行转义。
转义规则如下:
字符转义后的字符U+2028 \u2028
U+2029 \u2029
< \u003c
修复后的代码如下:
<script>var initData = <%= escapeEmbedJSON(data.toJSON()) %>
通过这个事件,小明学习到了如下知识:
HTML 转义是非常复杂的,在不同的情况下要采用不同的转义规则。如果采用了错误的转义规则,很有可能会埋下 XSS 隐患。
应当尽量避免自己写转义库,而应当采用成熟的、业界通用的转义库。
漏洞总结小明的例子讲完了,下面我们来系统的看下 XSS 有哪些注入的方法:
在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入。
在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。
在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。
在标签的 href、src 等属性中,包含 javascript: 等可执行代码。
在 onload、onerror、onclick 等事件中,注入不受控制代码。
在 style 属性和标签中,包含类似 background-image:url("javascript:..."); 的代码(新版本浏览器已经可以防范)。
在 style 属性和标签中,包含类似 expression(...) 的 CSS 表达式代码(新版本浏览器已经可以防范)。
总之,如果开发者没有将用户输入的文本进行合适的过滤,就贸然插入到 HTML 中,这很容易造成注入漏洞。攻击者可以利用漏洞,构造出恶意的代码指令,进而利用恶意代码危害数据安全。
XSS 攻击的分类通过上述几个例子,我们已经对 XSS 有了一些认识。
什么是 XSSCross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。
为了和 CSS 区分,这里把攻击的第一个字母改成了 X,于是叫做 XSS。
XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。
而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。
在部分情况下,由于输入的限制,注入的恶意脚本比较短。但可以通过引入外部的脚本,并由浏览器执行,来完成比较复杂的攻击策略。
这里有一个问题:用户是通过哪种方法“注入”恶意脚本的呢?
不仅仅是业务上的“用户的 UGC 内容”可以进行注入,包括 URL 上的参数等都可以是攻击的来源。在处理输入时,以下内容都不可信:
来自用户的 UGC 信息
来自第三方的链接
URL 参数
POST 参数
Referer (可能来自不可信的来源)
Cookie (可能来自其他子域注入)
XSS 分类