阅读 904

前端安全

1 浏览器安全

1.1 同源策略

是一种约定,是浏览器最核心也是最基本的安全功能。可以说,Web是构建在同源策略的基础之上,浏览器只是针对同源策略的一种实现。

浏览器的同源策略,限制了来自不同源的“document”或脚本,对当前“document”读取或设置某些属性。

来自不同源的对象无法互相干扰,当 JavaScript 被浏览器认为来自不同源时,请求被拒绝。

影响因素:host(域名或 IP 地址,如果是 IP 地址则看作一个根域名)、子域名、端口、协议。

注意:对于当前页面,页面内存放的 Javascript 文件的域并不重要,重要的是加载 Javascript 页面所在的域是什么。例如:当 a.com 页面加载了 b.com/b.js ,b.js 的源是 a.com。

<script>、 <img>、 <iframe>、<link>等标签通过 src 属性加载资源,可以跨域加载资源,而不受同源策略的限制,因为实质是由浏览器发起一次 GET 请求。

而 XMLHttpRequest、DOM、Cookie,浏览器限制了其对 JavaScript 的权限,故不能跨域访问资源。

==> W3C委员会制定跨域访问标准:通过目标域返回的 HTTP 头来授权是否允许跨域访问,因为 HTTP 头对于 Javascript 来说一般是无法控制的。(此方案的安全基础:Javascript 无法控制该 HTTP 头)。

第三方插件:Flash、Java、Applet、Silverlight、Google Gears 等都有自己的控制策略。

1.2 浏览器沙箱

Google Chrome 是第一个采取多进程架构的浏览器,其主要进程分为:浏览器进程、渲染进程、插件进程、扩展进程。

插件进程如flash、java、pdf 等与浏览器进程严格隔离,互不影响。

渲染引擎由 Sandbox 隔离,网页代码要与浏览器内核进程通信、与操作系统通信都需要通过 IPC channel,在其中会进行一些安全检查。

Sandbox 目的:让不可信任的代码运行在一定的环境中,限制其访问隔离区外的资源,如果一定要跨域边界产生数据交换,则只能通过指定的数据通道,比如经过封装的 API 来完成,在这些 API 中会严格检查请求的合法性。


虽然有进程架构和 Sandbox 的暴露,但仍有一些第三方插件不受 Sandbox 管辖。

1.3 恶意网站拦截

一般都是浏览器周期性地从服务器获取一份最新的恶意网站黑名单,如果用户访问的网址存在此黑名单中,则弹出一个警告页面。


2 跨站脚本攻击(XSS)

2.1 简介

跨站脚本攻击,Cross Site Script(简称 XSS)。指黑客通过“HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。因为最初的攻击案例时跨域的,所以称为“跨站脚本”。

本质:HTML 注入,用户的数据被当成了 HTML 代码的一部分来执行,从而混淆了原本的语义,产生了新的语义。

2.1.1 反射型 XSS

也称“非持久型XSS”,简单的把用户输入的数据“反射”给浏览器,即黑客往往需要诱使用户“点击”一个恶意链接才能攻击成功。

2.1.2 存储型XSS

也称“持久型XSS”,把用户输入的数据“存储”在服务器,具有很强的稳定性。例:访问黑客写下的一篇含有恶意 JavaScript 代码的博客文章,黑客把恶意脚本保存到服务端。

2.1.3 DOM Based XSS

从效果上来说,也是反射型XSS,单独划分出来,是因为其形成原因比较特别,指通过修改页面的 DOM 节点形成的 XSS。


2.2 XSS 攻击进阶

2.2.1 XSS Payload

XSS Payload 指完成各种攻击的恶意脚本,即 Javascript 脚本。

  • cookie劫持

防范措施:

- 在 Set-Cookie 时给关键 Cookie 植入 HttpOnly 标识;

- 把 Cookie 与客户端IP绑定

  • 构造 GET 和 POST 请求

    比如,删除某网站的某篇文章,往往只需要知道该文章的id,通过插入图片来发送一个GET 请求即可删除该文章。如果是一个 POST 请求,则可通过构造一个 form 表单 或 通过 XMLHttpRequest 。

  • XSS 钓鱼

    主要用在窃取密码,利用 Javascript 在当前页面“画出”一个伪造的登录框,当用户在登录框中输入用户名与密码后,其密码将被发送至黑客的服务器上。

  • 识别用户浏览器

    通过代码 alert(navigator.userAgent) 获取客户端的信息,但浏览器的 userAgent 是可以伪造的,所以通过分辨浏览器之间的版本差异更能准确的判断出浏览器的版本。

  • 识别用户安装的软件

  • CSS History Hack,通过CSS来获取用户曾经访问过的网站,因为早起的浏览器,用户访问过的网站其链接的颜色变得与众不同。

  • 获取用户的真实 IP 地址

    通过借助第三方软件来获取,比如客户端安装了 Java 环境(JRE),则可以通过调用 Java Applet 的接口获取客户端的本地 IP 地址。

  • 终极武器:XSS Worm (蠕虫)

2.2.2 XSS 构造技巧
  1. 利用字符编码

  2. 绕过长度限制。

    通过限制长度,来限制攻击者能输入的长度。

    最常用的“藏代码”的地方,就是“location.hash”,因为其内容不会再 HTTP 包中发送。

    利用注释绕过长度限制

  3. 使用 <base> 标签,定义了所有使用相对路径的标签的 hosting 地址。


2.3 XSS 的防御

浏览器自带的抗 XSS 的措施有 Firefox 的 CSP、Noscript 扩展等。

2.3.1 HttpOnly

浏览器将禁止页面的 Javascript 访问带有 HttpOnly 属性的 Cookie,主要是解决 Cookie 劫持攻击。

2.3.2 输入检查

限制用户的输入格式和规范,比如限制只能为数字和字母的组合,从而让一些基于特殊字符的攻击失效。

输入检查的逻辑,必须在服务端实现,因为客户端的检查也是狠容易被 攻击者绕过,现有的普遍做法是两端都做同样的检查,客户端的检查可以阻挡大部分误操作的正常用户,从而节约服务器资源。

XSS Filter:比较只能的输入检查,匹配 XSS 的特征,检查是否包含 ”JavaScript“,”<script>“等敏感字符。但其对 “<” 和 ">" 等字符的处理,可能会改变用户的数据语义,比如用户输入:1+1 < 3。

2.3.3 输出检查

一般来说,除了富文本的输出外,在变量输出到 HTML 页面时,可以使用编码或转义的方式来防御 XSS 攻击。

  1. 安全的编码函数

    针对 HTML 的编码方式:HtmlEncode,作用是将字符转换成 HTMLEntities。

    如:&(&amp;) , < (&lt;) , >(&gt;) , "(&quot;)

    JavaScript 的编码方式:JavascriptEncode,需要使用 “\” 对特殊字符进行转义。在对抗 XSS 是,要输出的变量必须在引号内部

    var x = 1;alert(1);      // 执行了 alert
    var y = " 1;alert(1)";   // 安全复制代码

    更严格的做法,除了数字和字母外的所有字符,都使用十六进制的方式进行编码。


3 跨站点请求伪造(CSRF)

跨站点请求伪造,Cross site Request Forgery。

指利用用户的身份操作用户账户的一种攻击方式。

即攻击者诱使用户访问一个页面,就以该用户身份在第三方站点里执行了一次操作。例:往页面加入一张不可显示的图片,其src是一个具有破坏性的请求,当用户正常访问时,该请求被触发。

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

攻击者只有预测到 URL 的所有参数与参数值,才能成功地构造一个伪造的请求;反之,攻击者将无法攻击成功。


3.1 CSRF 攻击

3.1.1 浏览器的 Cookie 策略

浏览器所持有的Cookie分为两种:

  • Session Cookie,临时Cookie。保存在浏览器进程的内存中,浏览器关闭即生效。

  • Third-party Cookie,本地Cookie。服务器在 Set-Cookie 时指定了 Expire 时间,过期才会生效,存在本地。

在浏览网站的过程中,即使浏览器新打开了 Tab 页,Session Cookie 也都是有效的,再发起 CSRF 攻击。

而如果浏览器从一个域的页面,要加载另一个域的资源,由于安全原因,某些浏览器会阻止 Third-party Cookie 的发送。

3.1.2P3P 头的副作用

P3P Header 是 W3C 制定的一项关于隐私的标准,全称是 The Platform for Privacy Preference。

如果网站返回给浏览器的 HTTP 头包含有 P3P 头,则在某种程度上来说,将允许 浏览器发送第三方 Cookie。在 IE 下即使是<iframe>、<script>等标签页将不再拦截第三方 Cookie 的发送。

主要应用在类似广告等需要跨域访问的页面。

P3P 头设置后,对于 Cookie 的影响将扩大到整个域中的所有页面,因为 Cookie 是以域和path为单位。

P3P 头只需要由网站设置一次即可,之后每次请求都会遵循此策略,而不需要再重复设置。

如果网站返回给浏览器的 HTTP 头包含有 P3P 头,则在某种程度上,将允许浏览器发送第三方 Cookie。

3.1.3 GET、POST 请求均可

大多数 CSRF 攻击,都是通过 <img> 、 <iframe> 、 <script> 等带 src 属性的标签,这类标签只能发送一次 GET 请求,而不能发送 POST 请求,由此也有了认为 CSRF 攻击只能由 GET 请求发起的错误观点。

构造一个 POST 请求,在一个页面中构造好一个 form 表单,然后使用 JavaScript 自动提交这个表单。设置一个隐藏在一个不可见的 iframe 窗口中,那么整个自动提交表单的过程,对于用户来说也是不可见的。

3.1.4 Flash CSRF

flash 中可以shying getURL,loadVars等方式发起请求。

3.1.5 CSRF Worm


3.2 CSRF 的防御

3.2.1 验证码

CSRF 攻击的过程,往往是在用户不知情的情况下构造的网络请求,而验证码强制用户必须与应用进行交互,才能完成最终请求。

3.2.2 Referer Check

检查请求是否来自合法的“源”,应用:防止图片盗链。

缺点:服务器并非什么时候都能取到 Referer,比如:用户出于隐私保护的考虑,限制 Referer 的发送。或从HTTPS 跳转到 HTTP,处于安全考虑,浏览器也不会发送 Referer。

3.2.3 Anti CSRF Token

把参数加密,或者使用一些随机数,从而让攻击者无法猜测到参数值,也就无法构造请求的 URL,也就无法发起 CSRF 攻击。

缺点:加密后的 URL 非常难读,对用户非常不友好。其次,加密的参数每次都改变,URL 无法被用户收藏。最后,普通参数也被加密或哈希,将会给数据分析工作带来很大的困扰,因为数据分析常常需要用到参数的明文。

更好的方案:Anti CSRF Token,保持原参数不变,新增一个参数token,值是随机的,不可预测的。

注意:token 要足够随机,不可预测。设置 token 的有效时间。 token 的保密性。

token 仅用于对抗 CSRF 攻击,当网站还存在 XSS 漏洞时,这个方案就无效了。因为在 XSS 攻击下,攻击者完全可以请求页面后,读出页面内容里的 Token 值,然后再构造一个合法的请求,这个过程又被称为 XSRF。

---

附:攻击例子:

<input id="keyword1" value="<script>alert('hello')</script>">
<button id="btnSubmit1">搜索</button>
<div id="result1"></div>

// 执行以下代码将会执行 alert('hello')
$('#btnSubmit1').on('click', function() {
    $('#result1').html('您搜索的关键词是:' + $('#keyword1').val())
})

// 执行以下代码将不会执行 alert('hello'),只会在页面中输出
$('#btnSubmit1').on('click', function() {
    $('#result1').text('您搜索的关键词是:' + $('#keyword2').val())
})复制代码

<button id="btnSubmit3">攻击2</button>

// 执行以下代码将会执行 alert(123)
$('#btnSubmit3').on('click', function() {
    $("body").append('<img class="hide" src="#" onerror="alert(123)" />')
})复制代码

<form id="attackForm" action="https://weibo.com" method="post">
  <input id="keyword4" value="">
  <button id="btnSubmit4">搜索</button>
</form>

// 表单攻击,当触发是,会跳转到攻击者指定的页面
$('#btnSubmit4').on('click', function() {
    document.querySelector('#attackForm').submit()
})复制代码

---


4 点击劫持(ClickJacking)

点击劫持,是一种视觉上的欺骗。攻击者使用一个透明的、不可见的 iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的 iframe 页面。

需要诱使用户与页面产生交互行为,攻击成本更高。


4.1 攻击方式

4.1.1 Flash 点击劫持
4.1.2 图片覆盖攻击

通过利用图片的 style,覆盖掉其他图片,例如覆盖掉网站的logo。此时点击此图片就会链接到其他网站。甚至可以将图片伪装成一个按钮,文字等跟网站相融合,此时不需要用户点击,也能达到攻击。

4.1.3 拖拽劫持与数据窃取

拖拽是不受同源策略限制的。

“拖拽劫持”指诱使用户从隐藏的不可见 iframe 中“拖拽”出攻击者希望得到的数据,然后放到攻击者能控制的另一个页面中,从而窃取数据。


4.2 防御方式

一般是通过禁止跨域的 iframe 来防范。

4.2.1 frame busting

指通过写一段 JavaScript 代码,以禁止 iframe 的嵌套。

例如:

if(top.location != location) {• top.location = self.location;}复制代码
  • DENY:浏览器会拒绝当前页面加载任何 frame 页面;

  • SAMEORIGIN:则 frame 页面的地址只能为同源域名下的页面;

  • ALLOW-FROM origin:允许 frame 加载

三个值:

X-Frame-Options 是一个 HTTP 头,为了解决 ClickJacking 而生的。

4.2.2 X-Frame-Options

缺点:控制能力不强,通过嵌套多个 iframe 的方法可绕过。


5 HTML5 安全

5.1 HTML5 新标签

5.1.1 新标签的 XSS

<video> 、 <audio> 标签,来远程加载一段视频或音频。

5.1.2 iframe 的 sandbox

新增的 sandbox 属性,iframe 标签加载的内容将被视为一个独立的“源”,其中的脚本将被禁止执行,表单被禁止提交,插件被禁止加载,只想其他浏览器对象的链接也会被禁止。

sandbox 属性的值:

  • allow-same-origin: 允许同源访问;

  • allow-top-nabigation: 允许访问顶层窗口;

  • allow-forms: 允许提交表单;

  • allow-scripts: 允许执行脚本。

5.1.3 Link Types:noreferrer

h5 中 a 标签和 area 标签,定义了一个新的 Link Types:noreferrer,指定该属性之后,浏览器在请求该标签指定的地址时将不再发送 Referer。

这种设计是为了保护敏感信息和隐私。

5.1.4 Canvas 的妙用

canvas 标签可以让 Javascript 可以在页面中直接操作图片对象,也可以直接操作像素,构造出图片区域。

攻击:可以通过操作 canvas 中的每个像素点,完成验证码的绘制。


5.2 其他安全问题

5.2.1 跨域问题的处理

当服务端设置 Access-Control-Allow-Origin: * 时,用了通配符“*”,允许来自任意域的跨域请求,这是极其危险的。

5.2.2 postMessage 跨窗口传递信息

postMessage 允许每一个 window(包括当前窗口、弹出窗口、iframes等)对象往其他的窗口发送文本消息,从而实现跨窗口的消息传递。并且这个功能不受同源策略限制。

  • 必要时,在接受窗口验证 Domain,甚至验证URL,以防止来自非法页面的消息。实际上是在代码上实现一次同源策略的验证过程。

  • 接受窗口对接口的信息进行安全检查。

5.2.3 Web Storage

Web Storage 分为 Session Storage 和 Local Storage。

虽然受同源策略的约束,但当存有敏感信息时,也可能会成为攻击的目标。