web安全、同源策略、跨域、 CORS之间的关系

前言

以往也了解过同源策略、跨域等方面的知识,但都是零零散散的,也没深入思考相互之间的联系,本文旨在通过将相关的知识点串联起来,系统性的归纳总结。

关系示意图.png

一、同源策略是什么?

同源策略限制了从同一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

1.1 怎么才算是同源?

同时满足以下3个条件:

  1. 协议
    http 和 https 会被算作不同
  2. 域名
    注意二级域名和主域名会被算作不同
  3. 端口
1.2 同源策略具体限制了什么
  1. 无法读取非同源网页的 Cookie、LocalStorage、IndexedDB
  2. 无法接触非同源网页的 DOM
  3. 向非同源地址发送 AJAX 请求,浏览器会拦截请求的响应。

二、为什么要有同源策略?

试想一下,如果没有同源策略,会发生什么?
随便举几个例子,如果没有 1.2 中的种种限制,下面的情况很容易发生:

  1. 嵌套第三方网页,并修改第三方网页的 DOM 结构
  2. xss攻击难度降低
    在有同源策略之后,需要向被攻击站点注入脚本才能获取 LocalStorage、Cookie 中的信息,如果没有同源限制,只要被攻击者访问过其他站点,再访问攻击者的站点,攻击者站点中的脚本可直接获取被攻击者之前访问过的站点的信息了,都不需要注入脚本了。
  3. csrf 攻击
    既然能轻易获取到 cookie 等信息,可以直接通过 AJAX 发起伪造请求了。

通过以上 3 个例子可以看出,安全隐患太严重了,必须要引入同源策略来规避风险。

三、同源策略带来的问题

事物具有两面性,同源策略降低了安全风险的同时,也带来了很多不便。

再举几个例子:

  1. 前后端分离时期的 AJAX 跨域请求
  2. 新站点嵌套了部分旧站点页面,需要通信

不同源的站点或地址之间的通信被阻断,即常见的跨域问题

四、如何解决跨域

首先说明一点,跨域不仅仅包括 ajax 请求这一种情况,不同源的网页之间也有通信的需要。

(一) AJAX

4.1 JSONP

原理:

  1. <script> 标签的 src 属性是不受同源限制的(<img> 标签也是如此)
  2. 先提前定义好一个回调函数
function foo(data) {
  console.log(data);
}
  1. 将 foo 当做请求参数传递到服务器
  2. 服务器解析参数,获取 foo
  3. 服务器从数据库获取业务数据 data
  4. 服务器返回响应 foo(data) , 即把 data 当做参数
  5. 因为是通过 <script> 请求的,所以得到的响应就相当于请求回来一段 js 脚本,然后执行。

缺点:只支持 GET 请求。

4.2 CORS

CORS 全称是跨域资源共享(Cross-origin resource sharing)
详细请查看我的另一篇文章 CORS 学习笔记

4.3 Access-Control-Allow-Origin 白名单

其实就是 CORS 的具体实现。

服务端设置 header 头

Access-Control-Allow-Origin: *;

一般开发平台提供的 API 都是这样做的。但是对于不想开放的平台,使用 '*' 存在较大的安全风险,建议使用精确的域名来控制。

额外解答:为什么 Access-Control-Allow-Credentials: true; 时,不能设置 Access-Control-Allow-Origin 的值为 *
我的思考结论:Access-Control-Allow-Credentials 字段用来控制对带凭证的请求,服务器是否返回响应,Access-Control-Allow-Origin 字段用来控制请求的资源是否允许访问,我们先假设允许问题中的设置,会出现什么情况呢?会出现:一个携带凭证的跨域请求可以得到请求结果,猛一看好像没啥问题啊,我们平时开发不就为了实现跨域请求嘛,可是如果这个请求是伪造的呢?即 csrf 攻击,因为 Access-Control-Allow-Origin: * 所以同源策略中对于不同源 AJAX 请求的限制没了,这很容易造成安全问题。这里细心的同学会发现,那和 Access-Control-Allow-Credentials: true; 有什么关系呢?我的理解是,为什么请求需要带凭证呢,或者说什么样的请求需要带凭证?这样想就会明白,肯定是重要的资源,有安全要求,不想轻易被访问,所以服务器会对凭证进行校验,校验通过后才会返回响应的,因为像是开发平台这样的站点就是让别人请求的,所以设置Access-Control-Allow-Origin: *不会有问题,核心思想就是“重要的资源,不应该允许任意站点请求”,这个问题解释完了。

4.4 WebSocket

webSocket 是不受同源限制的。

4.5 代理服务器

浏览器请求同源服务器,服务器负责请求外部服务器。
举例:nginx 反向代理

(二) Cookie

4.6 设置 cookie 的 domain 属性

cookie 有个 domain 属性,用来设置 cookie 的作用域(结合 cookie 的另一个属性 path 使用)。

如果子域名 a.mozilla.org 和 b.mozilla.org 想要共享一段 cookie ,只要将 cookie 的 domain 属性设置成共同的父域名 domain=mozilla.org 即可。

4.7 document.domain

这里阮一峰的方法是在两个子站点中通过脚本设置 document.domain='mozilla.org'

缺点:

  • 不方便,因为需要协作的站点都要执行上述脚本才行,原因:document.domain = xxx会导致端口号被重置为null。
  • 不适合只需要共享部分 cookie 的需求

优点:document.domain 可以达到让父子域或者多个子域变成同源,作用不局限于 cookie 的共享。

(三) Iframe 跨窗口通信

4.8 片段识别符

指 url 中 # 后面的部分, 把需要传递的数据放到片段识别符中。

父窗口改变子窗口的片段标识符:

let src = originURL + '#' + data;
document.getElementById('childIFrame').src = src;

子窗口改变父窗口的片段标识符:

parent.location.href = target + '#' + hash;

监听 hash 的变化

window.onhashchange = function () {
  let msg = window.location.hash;
}

缺点:

  • url 长度有限,不能传递太多的数据
  • 不是标准规范
4.9 window.postMessage()

跨文档通信 API(Cross-document messaging)为 window 对象提供了postMessage(),允许跨窗口通信,无论是否同源。

语法:otherWindow.postMessage(message, targetOrigin, [transfer]);

父窗口向子窗口发送消息:

let pop = window.open('http://bbb.com', 'title');
pop.postMessage('hello world', 'http://bbb.com');

子窗口向父窗口发送消息:

window.opener.postMessage('I received', 'http://aaa.com');

监听消息:

window.addEventListener('message', function(e) {
  console.log(e.data);
})
  • event.source:发送消息的窗口
  • event.origin: 消息发向的网址
  • event.data: 消息内容

安全

  • 不希望从其他网站接收 message,请不要为 message 添加事件监听。
  • 始终使用 originsource 属性验证发件人的身份。
  • 向其他窗口发送数据时,指定精确的 origin

参考

阮一峰:同源策略
阮一峰:CORS
会编程的银猪:同源策略和跨域请求研究
MDN:Same-origin_policy
MDN:postMessage
MDN:CORSNotSupportingCredentials
MDN:Access-Control-Allow-Credentials

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容