您好、欢迎来到现金彩票网!
当前位置:满堂彩 > 次要防御方向 >

前端安全系列(一):如何防止XSS攻击?

发布时间:2019-07-25 00:52 来源:未知 编辑:admin

  随着互联网的高速发展,信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点。在移动互联网时代,前端人员除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。当然,浏览器自身也在不断在进化和发展,不断引入 CSP、Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行“查漏补缺”。

  近几年,美团业务高速发展,前端随之面临很多安全挑战,因此积累了大量的实践经验。我们梳理了常见的前端安全问题以及对应的解决方案,将会做成一个系列,希望可以帮助前端人员在日常开发中不断预防和修复安全漏洞。本文是该系列的第一篇。

  1.XSS 防范是后端 RD(研发人员)的责任,后端 RD 应该在所有用户提交数据的接口,对敏感字符进行转义,才能进行下一步操作。

  2.所有要插入到页面上的数据,都要通过一个敏感字符过滤函数的转义,过滤掉通用的敏感字符后,就可以插入到页面中。

  XSS 攻击是页面被注入了恶意的代码,为了更形象的介绍,我们用发生在小明同学身边的事例来进行说明。

  某天,公司需要一个搜索页面,根据 URL 参数决定关键词的内容。小明很快把页面写好并且上线。代码如下:

  小明带着一种不祥的预感点开了这个链接 [请勿模仿,确认安全的链接才能点开] 。果然,页面中弹出了写着XSS的对话框。

  这里不仅仅 div 的内容被注入了,而且 input 的 value 属性也被注入, alert 会弹出两次。

  其实,这只是浏览器把用户的输入当成了脚本进行了执行。那么只要告诉浏览器这段内容是文本就可以了。

  恶意代码都被转义,不再被浏览器执行,而且搜索词能够完美的在页面显示出来。

  通常页面中包含的用户输入内容都在固定的容器或者属性内,以文本的形式展示。

  攻击者利用这些页面的用户输入片段,拼接特殊格式的字符串,突破原有位置的限制,形成了代码片段。

  攻击者通过在目标网站上注入脚本,使之在用户的浏览器上运行,从而引发潜在风险。

  通过 HTML 转义,可以防止 XSS 攻击。 [事情当然没有这么简单啦!请继续往下看] 。

  自从上次事件之后,小明会小心的把插入到页面中的数据进行转义。而且他还发现了大部分模板都带有的转义配置,让所有插入到页面中的数据都默认进行转义。这样就不怕不小心漏掉未转义的变量啦,于是小明的工作又渐渐变得轻松起来。

  不久,小明又收到安全组的神秘链接:。小明不敢大意,赶忙点开页面。然而,页面并没有自动弹出万恶的“XSS”。

  虽然代码不会立即执行,但一旦用户点击a标签时,浏览器会就会弹出“XSS”。

  在这里,用户的数据并没有在位置上突破我们的限制,仍然是正确的 href 属性。但其内容并不是我们所预期的类型。

  原来不仅仅是特殊字符,连javascript:这样的字符串如果出现在特定的位置也会引发 XSS 攻击。

  小明欲哭无泪,在判断 URL 开头是否为javascript:时,先把用户输入转成了小写,然后再进行比对。

  不过,所谓“道高一尺,魔高一丈”。面对小明的防护策略,安全组就构造了这样一个连接:

  某天,小明为了加快网页的加载速度,把一个数据通过 JSON 的方式内联到 HTML 中:

  1.当 JSON 中包含U+2028或U+2029这两个字符时,不能作为 JavaScript 的字面量使用,否则会抛出语法错误。

  2.当 JSON 中包含字符串 时,当前的 script 标签将会被闭合,后面的字符串内容浏览器会按照 HTML 进行解析;通过增加下一个script标签等方法就可以完成注入。

  1.HTML 转义是非常复杂的,在不同的情况下要采用不同的转义规则。如果采用了错误的转义规则,很有可能会埋下 XSS 隐患。

  在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)。

  在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签。

  在 style 属性和标签中,包含类似expression(…)的 CSS 表达式代码(新版本浏览器已经可以防范)。

  总之,如果开发者没有将用户输入的文本进行合适的过滤,就贸然插入到 HTML 中,这很容易造成注入漏洞。攻击者可以利用漏洞,构造出恶意的代码指令,进而利用恶意代码危害数据安全。

  Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。

  为了和 CSS 区分,这里把攻击的第一个字母改成了 X,于是叫做 XSS。

  XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

  而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。

  在部分情况下,由于输入的限制,注入的恶意脚本比较短。但可以通过引入外部的脚本,并由浏览器执行,来完成比较复杂的攻击策略。

  不仅仅是业务上的“用户的 UGC 内容”可以进行注入,包括 URL 上的参数等都可以是攻击的来源。在处理输入时,以下内容都不可信:

  2.用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。

  4.恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

  这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

  2.用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。

  4.恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

  反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。

  反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。

  由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。

  POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。

  3.用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。

  4.恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

  DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

  针对第一个要素:我们是否能够在用户输入的过程,过滤掉用户输入的恶意代码呢?

  答案是不可行。一旦攻击者绕过前端过滤,直接构造请求,就可以提交恶意代码了。

  那么,换一个过滤时机:后端在写入数据库前,对输入进行过滤,然后把“安全的”内容,返回给前端。这样是否可行呢?

  我们举一个例子,一个正常的用户输入了5 7这个内容,在写入数据库前,被转义,变成了5 7。

  1.用户的输入内容可能同时提供给前端和客户端,而一旦经过了escapeHTML(),客户端显示的内容就变成了乱码(5 7)。

  当5 7通过 Ajax 返回,然后赋值给 JavaScript 的变量时,前端得到的字符串就是转义后的字符。这个内容不能直接用于 Vue 等模板的展示,也不能直接用于内容长度计算。不能用于标题、alert 等。

  所以,输入侧过滤能够在某些情况下解决特定的 XSS 问题,但会引入很大的不确定性和乱码问题。在防范 XSS 攻击时应避免此类方法。

  当然,对于明确的输入类型,例如数字、URL、电话号码、邮件地址等等内容,进行输入过滤还是必要的。

  既然输入过滤并非完全可靠,我们就要通过“防止浏览器执行恶意代码”来防范 XSS。这部分分为两类:

  存储型和反射型 XSS 都是在服务端取出恶意代码后,插入到响应 HTML 里的,攻击者刻意编写的“数据”被内嵌到“代码”中,被浏览器所执行。

  1.浏览器先加载一个静态 HTML,此 HTML 中不包含任何跟业务相关的数据。

  在纯前端渲染中,我们会明确的告诉浏览器:下面要设置的内容是文本(),还是属性(.setAttribute),还是样式(.style)等等。浏览器不会被轻易的被欺骗,执行预期外的代码了。

  在很多内部、管理系统中,采用纯前端渲染是非常合适的。但对于性能要求高,或有 SEO 需求的页面,我们仍然要面对拼接 HTML 的问题。

  如果拼接 HTML 是必要的,就需要采用合适的转义库,对 HTML 模板各处插入点进行充分的转义。

  常用的模板引擎,如 doT.js、ejs、FreeMarker 等,对于 HTML 转义通常只有一个规则,就是把& /这几个字符转义掉,确实能起到一定的 XSS 防护作用,但并不完善:

  注意:要根据项目情况进行过滤,禁止掉javascript:链接、非法scheme等

  可见,HTML 的编码是十分复杂的,在不同的上下文里要使用相应的转义规则。

  DOM 型 XSS 攻击,实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。

  虽然在渲染页面和执行 JavaScript 时,通过谨慎的转义可以防止 XSS 的发生,但完全依靠开发的谨慎仍然是不够的。以下介绍一些通用的方案,可以降低 XSS 带来的风险和后果。

  对于不受信任的输入,都应该限定一个合理的长度。虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。

  上述经历让小明收获颇丰,他也学会了如何去预防和修复 XSS 漏洞,在日常开发中也具备了相关的安全意识。但对于已经上线的代码,如何去检测其中有没有 XSS 漏洞呢?

  小明只要在网站的各输入框中提交这个字符串,或者把它拼接到 URL 参数上,就可以进行检测了。

  1.XSS 防范是后端 RD 的责任,后端 RD 应该在所有用户提交数据的接口,对敏感字符进行转义,才能进行下一步操作。

  防范存储型和反射型 XSS 是后端 RD 的责任。而 DOM 型 XSS 攻击不发生在后端,是前端 RD 的责任。防范 XSS 是需要后端 RD 和前端 RD 共同参与的系统工程。

  2.所有要插入到页面上的数据,都要通过一个敏感字符过滤函数的转义,过滤掉通用的敏感字符后,就可以插入到页面中。

  不同的上下文,如 HTML 属性、HTML 文字内容、HTML 注释、跳转链接、内联 JavaScript 字符串、内联 CSS 样式表等,所需要的转义规则不一致。

  业务 RD 需要选取合适的转义库,并针对不同的上下文调用不同的转义规则。

  整体的 XSS 防范是非常复杂和繁琐的,我们不仅需要在全部需要转义的位置,对数据进行对应的转义。而且要防止多余和错误的转义,避免正常的用户输入出现乱码。

  虽然很难通过技术手段完全避免 XSS,但我们可以总结以下原则减少漏洞的产生:

  在 FreeMarker 中,确保引擎版本高于 2.3.24,并且选择正确的。

  前端采用拼接 HTML 的方法比较危险,如果框架允许,使用createElement、setAttribute之类的方法实现。或者采用比较成熟的渲染框架,如 Vue/React 等。

  通过 CSP、输入长度配置、接口安全措施等方法,增加攻击的难度,降低攻击的后果。

  攻击者发现这个 URL 的参数uin、domain未经转义直接输出到 HTML 中。

  用户点击这个 URL 时,服务端取出 URL 参数,拼接到 HTML 响应中:

  用户点击这个 URL 时,服务端取出请求 URL,拼接到 HTML 响应中:

  浏览器接收到响应后就会加载执行恶意脚本,在恶意脚本中利用用户的登录状态进行关注、发微博、发私信等操作,发出的微博和私信可再带上攻击 URL,诱导更多人点击,不断放大攻击范围。这种窃用受害者身份发布恶意内容,层层放大攻击范围的方式,被称为“XSS 蠕虫”。

  2.完善的转义库需要针对上下文制定多种规则,例如 HTML 属性、HTML 文字内容、HTML 注释、跳转链接、内联 JavaScript 字符串、内联 CSS 样式表等等。

  通常,转义库是不能判断插入点上下文的(Not Context-Aware),实施转义规则的责任就落到了业务 RD 身上,需要每个业务 RD 都充分理解 XSS 的各种情况,并且需要保证每一个插入点使用了正确的转义规则。

  这种机制工作量大,全靠人工保证,很容易造成 XSS 漏洞,安全人员也很难发现隐患。

  所谓 Context-Aware,就是说模板引擎在解析模板字符串的时候,就解析模板语法,分析出每个插入点所处的上下文,据此自动选用不同的转义规则。这样就减轻了业务 RD 的工作负担,也减少了人为带来的疏漏。

  模板引擎经过解析后,得知三个插入点所处的上下文,自动选用相应的转义规则:

  以下是几个 XSS 攻击小游戏,开发者在网站上故意留下了一些常见的 XSS 漏洞。玩家在网页上提交相应的输入,完成 XSS 攻击即可通关。

  在玩游戏的过程中,请各位读者仔细思考和回顾本文内容,加深对 XSS 攻击的理解。

  前端安全系列文章将对 XSS、CSRF、网络劫持、Hybrid 安全等安全议题展开论述。下期我们要讨论的是 CSRF 攻击,敬请关注。

  XSS的修复难道不应该是在输出的时候进行处理么?“后端 RD 应该在所有用户提交数据的接口,对敏感字符进行转义”你这输入的时候进行转义算个什么事儿?

  输入做处理在输出的时候就可能需要再处理一次,但是输出的时候进行处理就只需要处理一次。

  请教一个问题,“2.当 JSON 中包含字符串 时,当前的 script 标签将会被闭合,后面的字符串内容浏览器会按照 HTML 进行解析;” 为什么当JSON中包含字符串时,script标签将会被闭合

  专注企业安全的精品内容分享平台,聚焦热点企业安全话题与策略方案,助推企业安全建设发展

  国内领先的互联网安全新媒体 FreeBuf 官方微博,专属于爱好者们交流、分享安全技术的社区

http://blogmarked.com/ciyaofangyufangxiang/275.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有