详解JS同源策略和CSRF

概述

本文主要涉及三个关键词:

  • 同源策略(Same-origin policy,简称 SOP)
  • 跨站请求伪造(Cross-site request forgery,简称 CSRF)
  • 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS)

同源策略 SOP

同源

先解释何为同源:协议、域名、端口都一样,就是同源。

url 同源
https://niconico.com 基准
https://niconico.com/spirit o
https://sub.niconico.com/spirit x
http://niconico.com/spirit x
https://niconico.com:8080/spirit x

限制

你之所以会遇到跨域问题,正是因为 SOP 的各种限制。但是具体来说限制了什么呢?

如果你说 SOP 就是“限制非同源资源的获取”,这不对,最简单的例子是引用图片、css、js文件等资源的时候就允许跨域。

如果你说 SOP 就是“禁止跨域请求”,这也不对,本质上 SOP 并不是禁止跨域请求,而是在请求后拦截了请求的回应。这就就会引起后面说到的 CSRF

其实SOP 不是单一的定义,而是在不同情况下有不同的解释:

  • 限制 cookies、DOM 和JavaScript的命名区域
  • 限制 iframe、图片等各种资源的内容操作
  • 限制 ajax 请求,准确来说是限制操作 ajax 响应结果,本质上跟上一条是一样的

下面是 3 个在实际应用中会遇到的例子:

  • 使用 ajax 请求其他跨域 API,最常见的情况,前端新手噩梦
  • iframe 与父页面交流,出现率比较低,而且解决方法也好懂
  • 对跨域图片(例如来源于<img>)进行操作,在 canvas 操作图片的时候会遇到这个问题

如果没有了 SOP:

  • 一个浏览器打开几个 tab,数据就泄露了
  • 你用 iframe 打开一个银行网站,你可以肆意读取网站的内容,就能获取用户输入的内容
  • 更加肆意地进行 CSRF

绕过跨域

SOP 带来安全,同时也会带来一定程度的麻烦,因为有时候就是有跨域的需求。绕过跨域的方案由于篇幅所限,并且网上也很多相关文章,所以不在这里展开解决跨域的方案,只给出几个关键词:

对于 ajax

  • 使用jsONP
  • 后端进行 CORS 配置
  • 后端反向代理

对于 iframe

  • 使用 location.hash 或 window.name 进行信息交流
  • 使用 postMessage

跨站请求伪造 CSRF

简述

CSRF(Cross-site request forgery)跨站请求伪造,是一种常见的攻击方式。是指 A 网站正常登陆后,cookie 正常保存,其他网站 B 通过某种方式调用 A 网站接口进行操作,A 的接口在请求时会自动带上 cookie。

上面说了,SOP 可以通过htmltag 加载资源,而且 SOP 不阻止接口请求而是拦截请求结果,CSRF 恰恰占了这两个便宜。

所以 SOP 不能作为防范 CSRF 的方法。

对于 GET 请求,直接放到<img>就能神不知鬼不觉地请求跨域接口。

对于 POST 请求,很多例子都使用 form 提交:

<form action="<nowiki>http://bank.com/transfer.do</nowiki>" method="POST">
  <input type="hidden" name="acct" value="MARIA" />
  <input type="hidden" name="amount" value="100000" />
  <input type="submit" value="View my pictures" />
</form>

归根到底,这两个方法不报跨域是因为请求由html控制,你无法用 js 直接操作获得的结果。

SOP 与 ajax

对于 ajax 请求,在获得数据之后你能肆意进行 js 操作。这时候虽然同源策略会阻止响应,但依然会发出请求。因为执行响应拦截的是浏览器而不是后端程序。事实上你的请求已经发到服务器并返回了结果,但是迫于安全策略,浏览器不允许你继续进行 js 操作,所以报出你熟悉的blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.。

所以再强调一次,同源策略不能作为防范 CSRF 的方法。

不过可以防范 CSRF 的例外还是有的,浏览器并不是让所有请求都发送成功,上述情况仅限于简单请求,相关知识会在下面 CORS 一节详细解释。

CSRF 对策

SOP 被 CSRF 占了便宜,那真的是一无是处吗?

不是!是否记得 SOP 限制了 cookie 的命名区域,虽然请求会自动带上 cookies,但是攻击者无论如何还是无法获取 cookie 的内容本身。

所以应对 CSRF 有这样的思路:同时把一个 token 写到 cookie 里,在发起请求时再通过 query、body 或者 header 带上这个 token。请求到达服务器,核对这个 token,如果正确,那一定是能看到 cookie 的本域发送的请求,CSRF 则做不到这一点。(这个方法用于前后端分离,后端渲染则可以直接写入到 dom 中)

示例代码如下:

var csrftoken = Cookies.get('csrfToken')

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return /^(GET|HEAD|OPTIONS|TRACE)$/.test(method)
}
$.ajaxSetup({
  beforeSend: function(xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader('x-csrf-token', csrftoken)
    }
  },
})

跨域资源共享 CORS

跨域是浏览器限制,但是如果服务器设置了 CORS 相关配置,在返回服务器的信息头部会加上Access-Control-Allow-Origin,浏览器看到这个字段的值与当前的源匹配,就会解锁跨域限制。

HTTP/1.1 200 OK

Date: Sun, 24 Apr 2016 12:43:39 GMT

Server: Apache

Access-Control-Allow-Origin: http://www.acceptmeplease.com

Keep-Alive: timeout=2, max=100

Connection: Keep-Alive

Content-Type: application/xml

Content-Length: 423

对于 CORS,请求分两种。

简单请求

  • 请求方法使用 GET、POST 或 HEAD
  • Content-Type 设为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain

符合上面两个条件的都为 CORS 简单请求。简单请求都会直接发到服务器,会造成 CSRF。

预检请求

不符合简单请求要求的请求都需要先发送预检请求(Preflight Request)。浏览器会在真正请求前发送 OPTION 方法的请求向服务器询问当前源是否符合 CORS 目标,验证通过后才会发送正式请求。

例如使用 application/json 传参的 POST 请求就是非简单请求,会在预检中被拦截。

再例如使用 PUT 方法请求,也会发送预检请求。

上面提到的可以防范 CSRF 的例外,就是指预检请求。即使跨域成功请求预检,但真正请求并不能发出去,这就保证了 CSRF 无法成功。

CORS 与 cookie

与同域不同,用于跨域的 CORS 请求默认不发送 Cookie 和 HTTP 认证信息,前后端都要在配置中设定请求时带上 cookie。

这就是为什么在进行 CORS 请求时 axios 需要设置withCredentials: true。

下面是 node.js 的后台 koa框架的 CORS 设置:

/**
 * CORS middleware
 *
 * @param {Object} [options]
 *  - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header
 *  - {String|Array} allowMethods `Access-Control-Allow-Methods`, default is 'GET,HEAD,PUT,POST,DELETE,PATCH'
 *  - {String|Array} exposeHeaders `Access-Control-Expose-Headers`
 *  - {String|Array} allowHeaders `Access-Control-Allow-Headers`
 *  - {String|Number} maxAge `Access-Control-Max-Age` in seconds
 *  - {Boolean} credentials `Access-Control-Allow-Credentials`
 *  - {Boolean} keepHeadersOnError Add set headers to `err.header` if an error is thrown
 * @return {Function} cors middleware
 * @api public
 */

以上就是详解JS同源策略和CSRF的详细内容,更多关于JS同源策略和CSRF的资料请关注我们其它相关文章!

(0)

相关推荐

  • js同源策略详解

    本文较为详细的分析了js同源策略.分享给大家供大家参考.具体如下: 概念:同源策略是客户端脚本(尤其是Javascript)的重要的安全度量标准.它最早出自Netscape Navigator2.0,其目的是防止某个文档或脚本从多个不同源装载. 这里的同源指的是:同协议,同域名和同端口. 精髓: 它的精髓很简单:它认为自任何站点装载的信赖内容是不安全的.当被浏览器半信半疑的脚本运行在沙箱时,它们应该只被允许访问来自同一站点的资源,而不是那些来自其它站点可能怀有恶意的资源. 为什么要有同源限制?

  • Ajax跨域问题及解决方案(jsonp,cors)

    跨域 跨域有三个条件,满足任何一个条件就是跨域 1:服务器端口不一致  2:协议不一致  3:域名不一致 解决方案: 1.jsonp 在远程服务器上设法动态的把数据装进js格式的文本代码段中,供客户端调用和进一步处理:在前台通过动态添加script标签及src属性,表面看上去与ajax极为相似,但是,这和ajax并没有任何关系:为了便于使用及交流,逐渐形成了一中非正式传输协议,人们把它称作 jsonp . 代码如下: html: <body> <form action="/&q

  • jsonp跨域获取百度联想词的方法分析

    本文实例讲述了jsonp跨域获取百度联想词的方法.分享给大家供大家参考,具体如下: jsonp原理: 1.Web页面上用<script> 引入 js文件时则不受是否跨域的影响 (不仅如此,我们还发现凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>.<img>.<iframe>) 2.于是我们把数据放到服务器上,并且数据为json形式(因为js可以轻松处理json数据) 3.因为我们无法监控通过<script&g

  • 原生js实现ajax请求和JSONP跨域请求操作示例

    本文实例讲述了原生js实现ajax请求和JSONP跨域请求.分享给大家供大家参考,具体如下: 直接上代码: const ajax = (params = {}) => { const nowJson = params.jsonp ? jsonp(params) : json(params); function jsonp(params){ //创建script标签并加入到页面中 var callbackName = params.jsonp; var head = document.getEle

  • 跨域解决方案Jsonp原理解析

    这篇文章主要介绍了跨域解决方案Jsonp原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.什么是Jsonp? Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据. 为什么我们从不同的域(网站)访问数据需要一个特殊的技术( JSONP )呢?这是因为同源策略. 同源策略,它是由 Netscape 提出的一个著名的安全策略,现在所有支持 Ja

  • javascript使用链接跨域下载图片

    前言 图片是最常见的静态资源文件,可以从本地.外链获取图片,或者使用base64码展示.而canvas的toDataUrl() API可以将图片转base64码,然后模拟点击事件即可下载图片. 外链下载 在本地或者网站下载外链url图片时涉及到跨域,跨域会暴露自己的隐私,浏览器对跨域请求进行了限制,故需要设置crossOrigin为anonymous来允许跨域,浏览器会为这张图片的请求头附带Origin信息,告诉静态资源服务器,请在响应头中附带Access-Control-Allow-Metho

  • Java开发中解决Js的跨域问题过程解析

    这篇文章主要介绍了Java开发中解决Js的跨域问题过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 主流方法有JSONP和CORS两种,这里记一下后者的方式,理论基础就是在请求的时候在http请求头中添加如下属性: //指定允许其他域名访问 Access-Control-Allow-Origin:http://localhost:8989 如果后端用Java开发,在返回请求中可以添加如下属性 1.在跨域问题中,如果不操作cookie,只需

  • JavaScript同源策略和跨域访问实例详解

    本文实例讲述了JavaScript同源策略和跨域访问.分享给大家供大家参考,具体如下: 1. 什么是同源策略 理解跨域首先必须要了解同源策略.同源策略是浏览器上为安全性考虑实施的非常重要的安全策略. 何谓同源: URL由协议.域名.端口和路径组成,如果两个URL的协议.域名和端口相同,则表示他们同源. 同源策略: 浏览器的同源策略,限制了来自不同源的"document"或脚本,对当前"document"读取或设置某些属性. (白帽子讲web安全[1]) 从一个域上加

  • JSONP解决JS跨域问题的实现

    现代编程中前后端都已经是分开部署了,前端有自己的域,后端也有自己的域.由于浏览器同源策略的限制,非同源下的请求,就会产生跨域问题.解决跨域问题的方法有很多种,例如CORS(cross orign resources share)和JSONP.这里我就着重介绍一下jsonp的解决方案. 一:基础概念 同源策略:同一协议,同一域名,同一端口号.只要不满足三者其中一种都是属于跨域问题. 举几个简单的例子 1: https://www.a.com:8080到http://www.a.com:8080的请

  • 详解JS同源策略和CSRF

    概述 本文主要涉及三个关键词: 同源策略(Same-origin policy,简称 SOP) 跨站请求伪造(Cross-site request forgery,简称 CSRF) 跨域资源共享(Cross-Origin Resource Sharing,简称 CORS) 同源策略 SOP 同源 先解释何为同源:协议.域名.端口都一样,就是同源. url 同源 https://niconico.com 基准 https://niconico.com/spirit o https://sub.ni

  • 详解JS浏览器储存

    引言 随着对前端的了解越来越深入,了解到了很多种浏览器的存储方案,如 Cookie.LocalStorage等,哪这些存储方案有何异同,分别的适用场景又是什么呢. Cookie Cookie的来源 Cookie 被创造出来的本意并不是本地储存,而是为了辨别用户身份.众所周知,Http 协议是无状态的,也就是说你每一次发送给服务器的请求对于服务器来说都是孤立的,服务器不知道这这些请求来自于谁.比如你向购物车里面添加了一些商品,但是当发送结账请求的时候服务器懵了,我怎么知道你是谁,你买了什么呢.而使

  • Qiankun原理详解JS沙箱是如何做隔离

    目录 前言 复习一下沙箱 SanpshotSandbox LegacySandbox ProxySandbox 隔离原理 XXX is undefined 总结 前言 相信大家也知道 qiankun 有 SnapshotSandbox, LegacySandbox 和 ProxySandbox 这些沙箱,而它们又可以分为单例和多例两种模式,网上也有很多文章对其进行介绍. 但这些文章的关注点都是沙箱的环境恢复做的事,那 JS 的隔离到底是怎么做到的呢? 换个问法,当我写 window.a = 1

  • 详解JS中异常与错误处理的正确方法

    目录 简介 1 面向错误编程 1.1 墨菲定律 1.2 先判否 2. js 内置的错误处理 2.1 Error 类 2.2 throw 2.3 try catch 2.4 Promise.catch 3. 错误处理只有一次 总结 简介 首先,这篇文章一定会引起争议,因为对于错误处理从来就没有真正的标准答案,每个人都会有自己的主观意见. 我的理解毕竟也是片面,提出的想法主要是基于个人的经验总结,如果有异议,欢迎交流讨论. 为了能够尽量保持客观,我会将处理思想尽量前置,再围绕处理思想展开. 这样大家

  • 详解js几个绕不开的事件兼容写法

    本文介绍了详解js几个绕不开的事件兼容写法,分享给大家,具体如下: 1.键盘事件 keyCode 兼容性写法 var inp = document.getElementById('inp') var result = document.getElementById('result') function getKeyCode(e) { e = e ? e : (window.event ? window.event : "") return e.keyCode ? e.keyCode :

  • 详解JS数组Reduce()方法详解及高级技巧

    基本概念 reduce() 方法接收一个函数作为累加器(accumulator),数组中的每个值(从左到右)开始缩减,最终为一个值. reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组. 语法: arr.reduce(callback,[initialValue]) callback (执行数组中每个值的函数,包含四个参数) previousValue (上

  • 详解js中构造流程图的核心技术JsPlumb(2)

    前言:上篇详解js中构造流程图的核心技术JsPlumb介绍了下JsPlumb在浏览器里面画流程图的效果展示,以及简单的JsPlumb代码示例.这篇还是接着来看看各个效果的代码说明. 一.设置连线的样式和颜色效果代码示例 大概的效果如图: 这些效果看着很简单,那么,我们如何用代码去实现它呢.上章我们说过,JsPlumb的连线样式是由点的某些属性决定的,既然如此,我们就通过设置点的样式来动态改变连线的样式即可.来看代码: 首先来看看连线类型的那个select <div id="btn_line

  • 详解JS异步加载的三种方式

    一:同步加载 我们平时使用的最多的一种方式. <script src="http://yourdomain.com/script.js"></script> <script src="http://yourdomain.com/script.js"></script> 同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止后续的解析,只有当当前加载完成,才能进行下一步操作.所以默认同步执行才是安全的.但这样如果js中有输

  • 详解JS数值Number类型

    Number 问题 下面的问题你都能回答对了吗? 0.1 + 0.2 == 0.3 成立吗? .e-5 表示多少? 怎么表示8进制? 怎么转换进制? 如何将字符串转换成数值或整数?反过来呢?十六进制又怎么处理? parseInt(0x12, 16) 的返回值是多少?是0x12吗? Number.MAX_VALUE 为最大数值,(new Number(12)).MAX_VALUE 是多少? JavaScript中怎么进行四舍五入?如果保留3位小数的精度? 如何获取一个随机数?如何取整?如何向上取整

随机推荐