# 前端安全

前端安全分两类:CSRF、XSS

# XSS

XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击。攻击者在目标网站上注入恶意代码,当被攻击者登陆网站时就会执行这些恶意代码,这些脚本可以读取 cookie,session tokens,或者其它敏感的网站信息,对用户进行钓鱼欺诈,甚至发起蠕虫攻击等。

这些操作一般可以完成下面这些事情:

  1. 窃取Cookie。
  2. 监听用户行为,比如输入账号密码后直接发送到黑客服务器。
  3. 修改 DOM 伪造登录表单。
  4. 在页面中生成浮窗广告。

通常情况,XSS 攻击的实现有三种方式——存储型、反射型和文档型。原理都比较简单,先来一一介绍一下。

# 存储型

顾名思义就是将恶意脚本存储了起来,确实,存储型的 XSS 将脚本存储到了服务端的数据库,然后在客户端执行这些脚本,从而达到攻击的效果。

常见的场景是留言评论区提交一段脚本代码,例如:

<script src="http://恶意网站"></script><iframe></iframe>

如果前后端没有做好转义的工作,那评论内容存到了数据库,在页面渲染过程中直接执行, 相当于执行一段未知逻辑的 JS 代码,是非常恐怖的。

# 反射型

反射型XSS指的是恶意脚本作为网络请求的一部分

比如我输入:

http://sanyuan.com?q=<script>alert("你完蛋了")</script>

这样,在服务器端会拿到q参数,然后将内容返回给浏览器端,浏览器将这些内容作为HTML的一部分解析,发现是一个脚本,直接执行,这样就被攻击了。

思路肯定是没问题的,不过你可能会发现不起效果,这是因为浏览器针对script等一些危险标签的插入做了拦截过滤,当然了这难不倒我们,毕竟咱们也不能把我要干坏事写在脸上,这不尊重对手,所以咱们换种委婉一点的写法就行了:

http://sanyuan.com?q=<img src="" onerror="alert(document.cookie)" />

因为是插入一张图片,浏览器一般不会过滤拦截,然后我们把src置空使其触发onerror事件,间接地执行我们的恶意脚本。done!

之所以叫它反射型,是因为恶意脚本是通过作为网络请求的参数,经过服务器,然后再反射到HTML文档中,执行解析。

Web 服务器不会存储反射型 XSS 攻击的恶意脚本,这是和存储型 XSS 攻击不同的地方。

# 文档型

文档型的 XSS 攻击并不会经过服务端,而是作为中间人的角色,在数据传输过程劫持到网络数据包,然后修改里面的 html 文档!

DOM 型 XSS 攻击,实际上就是前端JavaScript代码不够严谨,把不可信的内容插入到了页面。在使用 .innerHTML.outerHTML.appendChilddocument.write()等API时要特别小心,不要把不可信的数据作为 HTML 插到页面上,尽量使用.innerText.textContent.setAttribute()等。

# 防范措施

明白了三种XSS攻击的原理,我们能发现一个共同点:都是让恶意脚本直接能在浏览器中执行

那么要防范它,就是要避免这些脚本代码的执行。

  1. 无论是在前端和服务端,都要对用户的输入进行转码或者过滤。
function escape(str) {
  str = str.replace(/&/g, '&amp;');
  str = str.replace(/</g, '&lt;');
  str = str.replace(/>/g, '&gt;');
  str = str.replace(/"/g, '&quto;');
  str = str.replace(/'/g, '&##39;');
  str = str.replace(/`/g, '&##96;');
  str = str.replace(/\//g, '&##x2F;');
  return str;
}

// 通过转义,将攻击代码变成
escape('<script>alert(1)</script>');
// &lt;script&gt;alert(1)&lt;&##x2F;script&gt;
  • 净化和过滤掉不必要的html标签,比如:<iframe>, <script>等;
  • 净化和过滤掉不必要的Javascript的事件标签,比如:onclick, onfocus
  • 转义单引号,双引号,尖括号等特殊字符,可以采用htmlencode编码 或者过滤掉这些特殊字符
  1. HttpOnly

很多XSS攻击脚本都是用来窃取Cookie, 而设置CookieHttpOnly属性后,禁止Javascript通过document.cookie获得Cookie的值。

  1. CSP

在服务端使用 HTTP 的Content-Security-Policy头部来指定策略,或者在前端设置meta标签。

例如下面的配置只允许加载同域下的资源:

<!-- 1. http 头部 -->
Content-Security-Policy: default-src 'self'

<!-- 2. meta -->
<meta http-equiv="Content-Security-Policy" content="form-action 'self'">

严格的 CSP 在 XSS 的防范中可以起到以下的作用:

  • 限制其他域下的资源加载。
  • 禁止向其它域提交数据。
  • 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
  • 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
  • 合理使用上报可以及时发现 XSS,利于尽快修复问题。
  1. 对于url链接(例如图片的src属性),那么直接使用encodeURIComponent来转义。

# CSRF

CSRF(Cross-site request forgery), 即跨站请求伪造。指的是黑客诱导用户点击链接,打开黑客的网站,然后黑客利用用户目前的登录状态发起跨站请求。

要完成一次CSRF攻击,受害者必须依次完成两个步骤:

  1. 受害者登录A站点,并保留了登录凭证(Cookie)。
  2. 攻击者诱导受害者访问了站点B。
  3. 站点B向站点A发送了一个请求,浏览器会默认携带站点A的Cookie信息。
  4. 站点A接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是无辜的受害者发送的请求。
  5. 站点A以受害者的名义执行了站点B的请求。
  6. 攻击完成,攻击者在受害者不知情的情况下,冒充受害者完成了攻击。
  7. 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等(来源不明的链接,不要点击)

# 防范措施

  1. Cookie的SameSite属性

CSRF攻击中重要的一环就是自动发送目标站点下的Cookie,然后就是这一份Cookie模拟了用户的身份。因此在Cookie上面下文章是防范的不二之选。

SameSite可以设置为三个值,StrictLaxNone

  • Strict模式下,浏览器完全禁止第三方请求携带Cookie。比如请求sanyuan.com网站只能在sanyuan.com域名当中请求才能携带 Cookie,在其他网站请求都不能。
  • Lax模式,就宽松一点了,但是只能在get方法提交表单况或者a标签发送get请求的情况下可以携带Cookie,其他情况均不能。
  • None模式下,也就是默认模式,请求会自动携带上 Cookie。
  1. Token验证(主流)
  • 服务端给用户生成一个token,加密后传递给用户
  • 用户在提交请求时,需要携带这个token
  • 服务端验证token是否正确
  1. Referer 验证

Referer 可以作为一种辅助手段,来判断请求的来源是否是安全的,但是鉴于 Referer 本身是可以被修改的,因此不能仅依赖于 Referer

  1. 二次验证

针对一些有危险性的请求操作(比如删除账号,提现转账)我们可以增加用户的二次,比如发起手机或者邮箱验证码检验,进而降低CSRF打来的危害。

# 文件上传漏洞

服务器未校验上传的文件,致使黑客可以上传恶意脚本等方式。

  1. 用文件头来检测文件类型,使用白名单过滤(有些文件可以从其中一部分执行,只检查文件头无效,例如 PHP 等脚本语言);
  2. 上传后将文件彻底重命名并移动到不可执行的目录下;
  3. 升级服务器软件以避免路径解析漏洞;
  4. 升级用到的开源编辑器;
  5. 管理后台设置强密码。