Ipad Safari iframe cookie 当浏览器默认禁用第三方COOKIE
前一阵子,我们发现高版本的Safari中默认会阻止第三方cookie,如下图所示。

问题
什么是第三方cookie呢?在访问一个网站A时,网站A算作第一方,如果网站A中引用了另一个网站X(网站X的域名与网站A的域名不同)的资源,这时这个网站X就被认为是第三方。需要注意的是,这儿区分不同网站的标准是域名是否相同,而不是这两个网站是否由同一个公司运营。比如,taobao.com和tmall.com被认为是两个网站,尽管它们都属于阿里集团。
在网站建设中,使用第三方资源非常常见,大多数据情况下,这并不会带来问题。不过有时候,我们可能希望能读写这个第三方域下的cookie,这时问题就来了。
比如我们有一个网站a.com,其中埋有一段JavaScript脚本,每当用户打开a.com中的页面时,这段脚本就会发送一个GET请求到x.com。这样,只需要分析x.com的日志,就可以了解a.com的访问情况。
如果只是要统计a.com的PV,那么只需要将x.com的日志中所有记录加起来就行了,但是,如果要统计UV呢?
这时就需要在x.com这个域下写一个cookie用于标识当前用户,比如叫USER_ID。当用户访问a.com的页面,也即发起到x.com的请求时,x.com的服务器检查x.com域下是否有USER_ID这个cookie,如果有则什么也不做,如果没有,则生成一个新的USER_ID并写入cookie。有了这个cookie之后,分析x.com的日志就可以同时得到a.com的PV与UV。整个打点过程如下图所示。

但问题是,x.com在这儿属于第三方域,在高版本的Safari浏览器中,向第三方域写cookie受到了阻止。带来的结果就是,用户每次访问a.com时,发向x.com的请求的cookie都为空,于是x.com的服务器每次都认为这是一个新访问者,每次都生成一个新的USER_ID写回去,但当同一个用户再访问下一个a.com的页面时,发向x.com的请求的cookie仍然为空。最后,分析x.com的日志时就会发现,访问PV没有变化,但UV却暴涨,几乎和PV持平。
或许有人会问,打点服务器为什么要使用第三方域x.com呢?如果使用与站点相同的域a.com不就没有问题了吗?的确,如果打点服务器与站点同域那就没有问题了,不过很多时候我们并不能做到这一点,比如我们可能需要向很多个域名完全不同的站点提供同一套打点服务。
这个问题目前并不算严重,因为还只有高版本的Safari有这样的限制。但是,Safari增加这个限制是为了保持用户隐私(因为有大量的广告站点滥用第三方cookie),很有可能在不久的将来其他浏览器也会跟进,因此我们不得不尽早寻找解决之道。
P3P方案在这儿也是走不通的,KISSY的开发者承玉曾经提出过一个解决方案,简单来说,就是使用POST来代替GET,这样就能继续在高版本的Safari中写入第三方cookie。但遗憾的是这个方案在Safari 5.1.4+的版本中失效了,估计Safari已经修复了漏洞。另外,Google曾经因为使用类似的方式继续在高版本Safari下读写第三方cookie而被告上法庭,在去年8月时被罚款2250万美元,也就是说,如果继续使用各种hack的方式绕过浏览器限制读写第三方cookie,有可能面临法律风险。而且随着浏览器不断升级,各种原来可用的hack方式也都陆续失效了。
因此,必须要寻找其他解决方案。
第二方方案
经过测试,我们发现目前Safari只会在第三方域下完全没有cookie时阻止第三方cookie,而第三方域下只要有过任意一个cookie,即可继续使用以前的方式顺利读写。但是,怎么才能在第三方域下写入第一个cookie呢?
我们测试了很多方案,包括iframe嵌套等,最后发现至少在Safari 6中,如果第三方域下完全没有cookie,那么就没有办法向其写入cookie,唯一的办法是将它变成第二方,也即让这个域在顶层窗口打开。也就是说,如果第三方域下没有cookie,要向它写入第一个cookie,要么将页面先跳到这个域,写入cookie,再跳回来,要么弹出一个新窗口,写入cookie,再关闭弹窗。
显然,这两种方案对用户体验来说都不好。
localStorage方案
我们注意到,高版本Safari只阻止了第三方cookie,并没有阻止第三方localStorage,于是,我们便有了一个更为激进的方案:放弃第三方cookie,使用localStorage来代替。
这个方案的本质是这样的:在a.com中嵌入一个w.com域的iframe,这个iframe读取localStorage(是w.com域下),取到各种原来需要保存在第三方cookie中的值,然后发送一个GET或POST请求到x.com,原来那些记录在cookie中随着HTTP请求头发送的信息则改为通过url参数(GET方式)或Form表单(POST方式)的形式发送。如果要发送的内容不多,那么可以使用GET方式发送,只需返回一个jsonp即可,然后iframe再将jsonp中的数据写入localStorage。如果需要发送的内容很多,有可能使URL超长,那么就需要使用POST方式发送,这时,需要在iframe中再创建一个iframe作为POST的target,然后新iframe再将数据用postMessage等方式传回原iframe,原iframe再写回localStorage。
整个过程(使用POST)如下图所示:

这个方案的问题是比较复杂,整个流程长了很多,需要用到一些HTML5特性,比如localStorage、postMessage等,不过好在不支持第三方cookie的浏览器基本上都是对HTML5支持良好的高版本浏览器。
就目前来看,比较保险的做法是新老方案并行,在老浏览器上继续使用第三方cookie,在高版本Safari等默认阻止第三方cookie的浏览器上使用新方案。虽然不完美,但确实是可行的。期待不久的将来能有一种更完美的方案。
后来发现第三个方案:
因为session和cookie都需要在客户端写文件,而cache不需要,故采用cache可以解决ipad safari iframe跨域用户认证问题,不用绕弯子了
Ipad Safari iframe cookie 当浏览器默认禁用第三方COOKIE的更多相关文章
- 解决Safari高版本浏览器中默认禁用第三方COOKIE(含demo)
前段时间在项目里遇到了一个比较头疼的问题,就是高版本的Safari中默认会阻止第三方cookie,这使得使用Safari浏览器的用户无法按照正常的业务逻辑进行操作. 问题展现 知识点 什么是第三方co ...
- cookie加密 当浏览器全面禁用三方 Cookie
cookie加密 cookie localstorage 区别 https://mp.weixin.qq.com/s/vHeRStcCUarwqsY7Y1rpGg 当浏览器全面禁用三方 ...
- Chrome 提标 您的浏览器限制了第三方Cookie...解决方法
最近升级Chrome后会出现 您的浏览器限制了第三方Cookie,这将影响您正常登录,您可以更改浏览器的隐私设置,解除限制后重试. 解决方法: chrome://flags/ 把这句复制到浏览器回车 ...
- Ajax跨域请求中的Cookie问题(默认不带cookie等凭证)
1.原生Ajax请求方式,设置跨域请求附带详细参数 var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xx ...
- 全局设置axios发送cookie(axios 默认不发送cookie)
import axios from 'axios' axios.defaults.withCredentials=true; 如图:
- session依赖cookie,如果浏览器禁用了cookie呢?
我们都知道session依赖cookie,因为服务器需要在每次请求中获取sessionId,然后找到客户端的session对象,如果浏览器禁用了cookie呢? 这个时候,就需要用到URL重写了,这种 ...
- Cookie 详解以及实现一个 cookie 操作库
Cookie 详解以及实现一个 cookie 操作库 cookie 在前端有着大量的应用,但有时我们对它还是一知半解.下面来看看它的一些具体的用法 Set-Cookie 服务器通过设置响应头来设置客户 ...
- iframe在ipad safari的显示
今 天要在web中嵌套一个网址或本地HTML,用到了iframe,在电脑上设置scrolling=‘auto’,宽度高度,会有滚动条出现.而在 ipad上会全部显示整个网页的宽度高度.scrollin ...
- js 如何判断浏览器是否禁用cookie
语法:navigator.cookieEnabled: 如果浏览器启用了cookie,该属性值为true.如果禁用了cookie,则值为false. navigator: JavaScript中的一个 ...
随机推荐
- HTML5 Canvas绘文本动画(使用CSS自定义字体)
一.HTML代码: <!DOCTYPE html> <html> <head> <title>Matrix Text - HTML5 Canvas De ...
- 提高网站性能的 5 个 Grunt任务//////////////////z
提高网站性能的 5 个 Grunt任务 时间 2015-03-06 09:13:02 极客头条 原文 http://hugnew.com/wordpress/提高网站性能的-5-个-grunt任务 ...
- jquery获取input表单值的代码
[导读] jquery取radio单选按钮的值$("input[name=items]:checked") val();jquery radio取值,checkbox取值,sele ...
- Thinking in UML-2-建模基础
建模的问题可以分为两个: 怎么建 模是什么 怎么建:角度不同决定了建模方向不同.所以首先要决定抽象的角度即建立这个模型的目的是什么. 模是什么:人+事+物+规则 我们这样来建立模型: 问题领域 = n ...
- 15. 星际争霸之php设计模式--策略模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- C#,JS获取mac地址
js: function MacInfo() { var locator = new ActiveXObject("WbemScripting.SWbemLocator"); va ...
- MongoDB数据库基本用法
show dbs:显示数据库列表 show collections:显示当前数据库中的集合(类似关系数据库中的表) show users:显示用户 use <db name>:切换当前 ...
- Unity本身制作keystore
网上有不少利用jdk生成keystore的介绍.本身复杂不容易理解.作为一个Unity游戏开发者,制作keystore不需要这么麻烦.应为Unity本身就自带了制作keystore的功能.下面介绍制作 ...
- MySQL and Postgres command equivalents (mysql vs psql)
MySQL and Postgres command equivalents (mysql vs psql) 博客分类: Database From: http://blog.endpoint.c ...
- hibernate映射的 关联关系:有 一对多关联关系,一对一关联关系,多对多关联关系,继承关系
hibernate环境配置:导包.... 单向n-1:单向 n-1 关联只需从 n 的一端可以访问 1 的一端 <many-to-one> 元素来映射组成关系: name: 设定待映射的持 ...