关于前端安全性问题 XSS CSRF 等

公司的安全部门偶尔会转个邮件反馈些被人找到的网站可能不安全的地方,这里整理下前端常见的安全问题,主要还是 XssCsrf

XSS

XSS - 跨站脚本攻击(Cross-site scripting)

最常见的攻击类型,攻击者可以利用这种漏洞在网站上注入恶意的脚本然后被浏览器执行。这些脚本可以任意读取 cookie,session tokens,或者其它敏感的网站信息,或者让恶意脚本重写HTML内容。

XSS 攻击可以分为3类:

  • 存储型(持久型)
  • 反射型(非持久型)
  • DOM型

存储型(持久型)

注入型脚本永久存储在目标服务器上。当浏览器请求数据时,脚本从服务器上传回并执行。

最常见的就是一些博客或者评论系统对输入的内容没做限制,导致了脚本被执行,特别是在一些使用富文本的场景需要严格过滤。

如何攻击

举个例子:

比如在 a.com 的网站内,被用户 a 评论了这样一段代码 <script>sendXxx(document.cookie)</script>,然后网站没做转义和过滤就直接被渲染在了页面内,会被浏览器所执行。

当用户 b 来访问这个页面时,就会发送自己的cookie给攻击者,cookie如果存储了用户的登录凭证,那就可以被攻击者来登录账户了…

以上是以 cookie 为例,实际当用户可以插入恶意代码了,也就可以对网页的访问用户为所欲为…

如何防御

  • 对输入输出内容做转义或者过滤处理。比如 <script>&lt;script&gt
  • 通过设置 content-security-policy 响应头,现在页面可加载的资源来源域

反射型(非持久型)

当用户点击一个恶意链接,或者提交一个表单,或者进入一个恶意网站时,注入脚本进入被攻击者的网站。

最常见的是构造一个恶意链接,链接携带了一些可执行的脚本被服务端或者客户端解析使用时没做过滤

如何攻击

举个例子:

比如 a.com/post?name=postname ,请求这个地址时服务器会取出 query 参数中的 name 并渲染在页面上,那攻击者可以故意生成 a.com/post?name=<script>sendXxx(document.cookie)</script> 这类链接并发布出去

当用户访问的时候会执行了恶意代码。

这里是以url为例,也可能是伪造一个form提交等形式

如何防御

  • 解决方案还是一样对输入输出内容做转义或者过滤处理

DOM型

DOM型和前面 反射型 是一样的,区别只是在于数据是否是有服务端渲染出来的。区别就是 js中 innerHTML 等其他操作Dom的方法插入的恶意代码。

提示:html5规定不执行 innerHTML插入的script标签,但是 <img src='..' onerror='alert(1)'> 这类脚本依旧会执行

如何防御

  • 对js通过外部获取的内容做转义,比如url,storage等
  • 纯文本使用 textContent 代替 innerHTML

CSRF

CSRF - 跨站请求伪造(Cross-Site Request Forgery)是一种冒充受信任用户,向服务器发送非预期请求的攻击方式。

CSRF攻击的核心:

  • 被攻击网站 Cookie 能够在三方网站内被发送,Chrome的SameSite 已经可以有效防止这类攻击
  • 被攻击网站 Cookie还未过期

如何攻击

举个例子:

用户先登录了网站 banka.com,然后访问了攻击者网站,网站内包含一个请求 http://www.banka.com/transfer.php?toBankId=11&money=100000000

假如这里没有其它校验,参数也是通过query获取,那如果用户访问攻击者网站刚好登录过 banka.com 且没过期,那悲剧就实际发生了。

实际的场景中攻击者可能通过图片链接发送get请求,也可以iframe内嵌form表单提交发送post请求

如何防护

  • 不使用cookie,比如使用 token做用户认证
  • csrf-token,其实就是在每个页面浏览时返回一个随机秘钥,然后用户在请求的时候再带上秘钥给服务端做校验,如果没有秘钥或者校验不通过就拒绝请求。
  • 请求refer 来源判断
  • 加验证码

refer 和 opener

  • document.referrer 可能被暴露网站的隐私信息,造成密码泄露都不安全的因素
  • window.opener 能获取到来源页面的window对象

如何防护

最简单的可以通过 a标签 noreferrer noopener 属性来避免该问题。

详细的防御可以参见这里:如何修改页面的refer、opener

Iframe

使用Iframe嵌套三方网站或者被三方网站嵌套都有一定的安全性,需要结合实际场景做配置。

被嵌套

这类常见的就是全屏嵌套无边框,所以在感知上和源站是一模一样,然后在一些敏感操作的时候在通过遮盖层来覆盖

比如:登录的输入框被覆盖,然后你以为你在正常的输入密码,实际是被伪造的输入框,你输入的内容直接输入到了对方的服务器上。

防御

  • 配置 X-FRAME-OPTIONS 响应头配置允许嵌套的网站。

    1. deny 完全禁止
    2. sameorigin 允许相同域名页面的嵌套
    3. allow-from 指定可嵌套的来源页,如:allow-from https://example.com/
  • js做限制,通过判断 self === top 不相等说明是被嵌套在 iframe 中

嵌套别人

一般来说嵌套别人的iframe都是可信的,也就不会有什么安全问题,如果不确定就不要引用,另外也可以通过 sandbox 属性来限制iframe。

CDN 劫持

对静态资源是否被篡改的检测,script 和 link 标签有了新的属性 integrity

使用SRI要保证两个条件:一是要保证 资源同域 或开启跨域,二是在 <script> 中 提供签名 以供校验。

github的link 如此:

1
<link crossorigin="anonymous" media="all" integrity="sha512-UDsGRotwx2k6kbfDX9jHfPF0usc3W8ZycpLWUkGPOl75fCsW4/G/yrOzGIXhNMNu7SZmLDXXQflOl6oT3S0GSg==" rel="stylesheet" href="https://github.githubassets.com/assets/github-503b06468b70c7693a91b7c35fd8c77c.css" />

详细的配置 查看这里SRI

参考