前端 安全

495 阅读11分钟

XSS(Cross Site SCripting)

  • 跨站脚本攻击,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户浏览器上运行来窃取用户敏感信息或者利用这些信息冒充用户向网站发起攻击
  • 根据攻击来源XSS攻击可分为三种类型:反射型,存储型,DOM型。

反射型

  • 恶意脚本本身是作为请求参数发送到站点页面存在漏洞的地方(通常是搜索框),然后脚本反射(出现)在新渲染(或者部分刷新)的页面并执行。
  • 漏洞常见于通过url传递参数的功能,如搜索等。攻击者构造一个带有恶意代码的url,当用户打开带有恶意代码的url,网站服务端将恶意代码从url中取出,拼接在HTML中返回给浏览器,用户浏览器解析后恶意代码也会执行,恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行操作。
  • 由于需要用户主动打开恶意的 URL 才能生效 , 攻击者往往会结合多种手段诱导用户点击。
  • POST 的内容也可以触发反射型 XSS , 只不过其触发条件比较苛刻 (需要构造表单提交页面 , 并引导用户点击),所以非常少见。 反射型XSS的攻击步骤:
  • 1.攻击者构造出特殊的URL, 其中包含恶意代码
  • 2.用户打开带有恶意代码的URL时, 网站服务端将恶意代码从 URL中取出, 拼接在 HTML中返回给浏览器
  • 3.用户浏览器接收到响应后解析执行, 混在其中的恶意代码也被执行。
  • 4.恶意代码窃取用户数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接口执行攻击者指定的操作。

存储型

  • 存储型(或HTML注入型/持久型)XSS攻击不需要用户点击特制链接,攻击者仅需要提交攻击代码到一个网站上其他用户可能访问的地方,比如用户评论、留言板等,当用户访问时攻击代码自动执行。
  • 存储型与反射型漏洞的区别是:存储型XSS恶意代码存在数据库中,反射型XSS的恶意代码存在url中。 存储型XSS的攻击步骤
  • 1.攻击者将恶意代码提交到目标网站的数据库中
  • 2.用户打开目标网站时 , 网站服务端将恶意代码从数据库取出, 拼接在 HTML中返回给浏览器
  • 3.用户浏览器接收到响应后解析执行, 混在其中的恶意代码也被执行。
  • 4.恶意代码窃取用户数据并发送到攻击者的网站, 或者冒充用户的行为, 调用目标网站接口执行攻击者指定的操作

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

DOM型

  • DOM型 XSS 攻击 , 实际上就是前端 javaScript 代码不够严谨 , 把不可信的内容插入到了页面 。在使用 .innerHTML , .outerHTML , appendChild , document.write()等 API 时要特别小心 , 不要把不可信的数据作为为 HTML 插入到页面上 , 尽量使用 .innerText , .textContent , setAttribute()等。 DOM型XSS 的攻击步骤:
  • 1.攻击者构造出特殊数据 , 其中包含恶意代码
  • 2.用户浏览器执行恶意代码
  • 3.恶意代码窃取用户数据并发送到攻击者的网站 , 或者冒充用户的行为 , 调用目标网站接口执行攻击者指定的操作。

通用型XSS

  • 通用型XSS,也叫做UXSS或者Universal XSS,全称Universal Cross-Site Scripting。
  • 上面三种XSS攻击的是因为客户端或服务端的代码开发不严谨等问题而存在漏洞的目标网站或者应用程序。这些攻击的先决条件是访问页面存在漏洞,但是UXSS是一种利用浏览器或者浏览器扩展漏洞来制造产生XSS的条件并执行代码的一种攻击类型。 漏洞成因
  • Web浏览器是正在使用的最流行的应用程序之一,当一个新漏洞被发现的时候,不管自己利用还是说报告给官方,而这个过程中都有一段不小的时间,这一过程中漏洞都可能被利用于UXSS。
  • 不仅是浏览器本身的漏洞,现在主流浏览器都支持扩展程序的安装,而众多的浏览器扩展程序可能导致带来更多的漏洞和安全问题。因为UXSS攻击不需要网站页面本身存在漏洞,同时可能访问其他安全无漏洞页面,使得UXSS成为XSS里危险和最具破坏性的攻击类型之一。

突变型XSS

  • 突变型XSS,也叫做mXSS或,全称Mutation-based Cross-Site-Scripting。(mutation,突变,来自遗传学的一个单词,大家都知道的基因突变,gene mutation) 漏洞成因
  • 然而,如果用户所提供的富文本内容通过javascript代码进入innerHTML属性后,一些意外的变化会使得这个认定不再成立:浏览器的渲染引擎会将本来没有任何危害的HTML代码渲染成具有潜在危险的XSS攻击代码。 随后,该段攻击代码,可能会被JS代码中的其它一些流程输出到DOM中或是其它方式被再次渲染,从而导致XSS的执行。 这种由于HTML内容进入innerHTML后发生意外变化,而最终导致XSS的攻击流程。 攻击流程
  • 将拼接的内容置于innerHTML这种操作,在现在的WEB应用代码中十分常见,常见的WEB应用中很多都使用了innerHTML属性,这将会导致潜在的mXSS攻击。从浏览器角度来讲,mXSS对三大主流浏览器(IE,CHROME,FIREFOX)均有影响。

XSS防御方法

  • 在使用 .innerHTML、.outerHTML、document.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent、.setAttribute() 等。DOM 中的内联事件监听器,如 location、onclick、onerror、onload、onmouseover 等, 标签的href属性,JavaScript 的eval()、setTimeout()、setInterval()等,都能把字符串作为代码运行。如果不可信的数据拼接到字符串中传递给这些 API,很容易 产生安全隐患,请务必避免。
  • 输入检查。对于用户的输入进行检查、转义、过滤等。建立可信任的字符和html标签白名单,对于不在白名单吧内的字符或者标签进行过滤或编码
  • 输入长度控制。对于不可信的输入应该限定一个合理的长度,虽然不能完全防止但可以增加攻击的难度
  • 设置HttpOnly,浏览器将禁止页面的JavaScript访问带有HttpOnly属性的cookie,来防止恶意脚本通过document.cookie访问到用户隐私数据
  • 现在主流浏览器内置了防范XSS的措施,如内容安全策略CSP(developer.mozilla.org/zh-CN/docs/…)
  • 如果拼接 HTML 是必要的,就需要采用合适的转义库,对 HTML 模板各处插入点进行充分的转义。常用的模板引擎,如 doT.js、ejs、FreeMarker 等,对于 HTML 转义通常只有一个规则,就是把 & < > " ' / 这几个字符转义掉,确 实能起到一定的 XSS 防护作用,但并不完善:这里推荐一个前端防止XSS攻击的插件: js-xss(juejin.cn/post/691334…) CSRF

  • CSRF(Cross-site-request-forgery) 跨站请求伪造: 攻击者诱导受害者进入第三方网站, 在第三方网站中 , 向被攻击网站发起跨域请求。利用受害者在被攻击网站已经获取的注册凭证 , 绕过后台的用户验证, 达到冒充用户对被攻击的网站执行某项操作的目的。 典型的CSRF攻击流程

  • 1.受害者登录 A 站点 , 并保留了登录凭证(Cookie)

  • 2.攻击者诱导受害者访问了站点B

  • 3.站点B向站点A发送了一个请求, 浏览器会默认携带站点A的Cookie信息。

  • 4.站点A接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是无辜的受害者发送的请求。

  • 5.站点A以受害者的名义执行了站点B的请求 攻击完成,攻击者在受害者不知情的情况下,冒充受害者完成了攻击

防御方法

  • 1.添加验证码(体验不好) 验证码能够防御CSRF攻击, 但是我们不可能每一次交互都需要验证码,否则用户的体验会非常差,但是我们可以在转账,交易等操作时, 增加验证码, 确保我们的账户安全。
  • 2.判断请求的来源:检测Referer和Origin(并不安全,Referer可以被更改) Referer 可以作为一种辅助手段,来判断请求的来源是否是安全的, 但是鉴于 Referer 本身是可以修改的 , 因此不能仅依赖于 Referer。 在HTTP协议中,每一个异步请求都会携带两个Header,用于标记来源域名:
Origin Header
Referer Header

这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个Header中的域名,确定请求的来源域。但是这两种都会出现不存在的情况。

Origin在以下两种情况下并不存在:


IE11同源策略: IE 11 不会在跨站CORS请求上添加Origin标头,Referer头将仍然是唯一的标识。最根本原因是因为IE 11对同源的定义和其他浏览器有不同,有两个主要的区别,可以参考MDN Same-origin_policy#IE_Exceptions


302重定向: 在302重定向之后Origin不包含在重定向的请求中,因为Origin可能会被认为是其他来源的敏感信息。对于302重定向的情况来说都是定向到新的服务器上的URL,因此浏览器不想将Origin泄漏到新的服务器上。

攻击者可以在自己的请求中隐藏Referer。如果攻击者将自己的请求这样填写:

 <img src="http://bank.example/withdraw?amount=10000&for=hacker" referrerpolicy="no-referrer"> 

复制代码那么这个请求发起的攻击将不携带Referer。 另外在以下情况下Referer没有或者不可信:

1.IE6、7下使用window.location.href=url进行界面的跳转,会丢失Referer。
2.IE6、7下使用window.open,也会缺失Referer。
3.HTTPS页面跳转到HTTP页面,所有浏览器Referer都丢失。
4.点击Flash上到达另外一个网站的时候,Referer的情况就比较杂乱,不太可信。
  • 3.使用Token(主流) CSRF攻击之所以能够成功, 是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的 Token。服务器通过校验请求是否携带正确的Token , 来把正常的请求和攻击请求区分开。跟验证码类似,只是用户无感知

步骤:

- 服务端给用户生成一个token, 加密后传递给用户。
- 用户在提交请求时, 需要携带这个token
- 服务端验证token是否正确
  • 4.Samesite Cookie属性 为了从源头上解决这个问题, Google 起草了一份草案来改进 HTTP协议 , 为 Set-Cookie 响应头新增 Samesite 属性 , 它用来表明这个 Cookie 是个 "同站Cookie" , 同站 Cookie只能作为第一方 Cookie, 不能作为第三方 Cookie, Samesite 有两个属性值 , 分别是 Strict 和 Lax。 部署简单, 并能有效防御 CSRF 攻击 , 但是存在兼容性问题

Samesite=Strict

Samesite=Strict 被成为是严格模式 , 表明这个 Cookie 在任何情况都不可能作为第三方的 Cookie, 有能力阻止所有 CSRF攻击。此时 , 我们在B 站点下发起对 A 站点的任何请求, A站点的 Cookie 都不会包含在 cookie请求头中。

参考链接