前一阵子,我们发现高版本的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的更多相关文章

  1. 解决Safari高版本浏览器中默认禁用第三方COOKIE(含demo)

    前段时间在项目里遇到了一个比较头疼的问题,就是高版本的Safari中默认会阻止第三方cookie,这使得使用Safari浏览器的用户无法按照正常的业务逻辑进行操作. 问题展现 知识点 什么是第三方co ...

  2. cookie加密 当浏览器全面禁用三方 Cookie

    cookie加密    cookie  localstorage    区别 https://mp.weixin.qq.com/s/vHeRStcCUarwqsY7Y1rpGg 当浏览器全面禁用三方 ...

  3. Chrome 提标 您的浏览器限制了第三方Cookie...解决方法

    最近升级Chrome后会出现  您的浏览器限制了第三方Cookie,这将影响您正常登录,您可以更改浏览器的隐私设置,解除限制后重试. 解决方法: chrome://flags/ 把这句复制到浏览器回车 ...

  4. Ajax跨域请求中的Cookie问题(默认不带cookie等凭证)

    1.原生Ajax请求方式,设置跨域请求附带详细参数 var xhr = new XMLHttpRequest(); xhr.open("POST", "http://xx ...

  5. 全局设置axios发送cookie(axios 默认不发送cookie)

    import axios from 'axios' axios.defaults.withCredentials=true; 如图:

  6. session依赖cookie,如果浏览器禁用了cookie呢?

    我们都知道session依赖cookie,因为服务器需要在每次请求中获取sessionId,然后找到客户端的session对象,如果浏览器禁用了cookie呢? 这个时候,就需要用到URL重写了,这种 ...

  7. Cookie 详解以及实现一个 cookie 操作库

    Cookie 详解以及实现一个 cookie 操作库 cookie 在前端有着大量的应用,但有时我们对它还是一知半解.下面来看看它的一些具体的用法 Set-Cookie 服务器通过设置响应头来设置客户 ...

  8. iframe在ipad safari的显示

    今 天要在web中嵌套一个网址或本地HTML,用到了iframe,在电脑上设置scrolling=‘auto’,宽度高度,会有滚动条出现.而在 ipad上会全部显示整个网页的宽度高度.scrollin ...

  9. js 如何判断浏览器是否禁用cookie

    语法:navigator.cookieEnabled: 如果浏览器启用了cookie,该属性值为true.如果禁用了cookie,则值为false. navigator: JavaScript中的一个 ...

随机推荐

  1. cocos2dx 3.x(实现帧动画(人物动画,跑马灯效果)的几种方法)

    //创建一个跑酷的精灵
  auto sprite = Sprite::create("1.png");
 //设置精灵的坐标
 sprite->setPosition(Ve ...

  2. dubbo源码分析1-reference bean创建

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

  3. Linux命令之md5sum

    1. 背景 在网络传输.设备之间转存.复制大文件等时,可能会出现传输前后数据不一致的情况.这种情况在网络这种相对更不稳定的环境中,容易出现.那么校验文件的完整性,也是势在必行的. md5sum命令用于 ...

  4. java实现求数组中元素第二大的元素

    /** * 找出数组中数第二大的值 * @param array * @date 2016-9-25 * @author shaobn */ public static void getMethod_ ...

  5. 免费的网络扫描器-Advanced IP Scanner

    软件会自动检测电脑所在的网段,自动决定扫描范围.(例如电脑IP是192.168.1.101,扫描范围就是192.168.1.*) 官方网站:http://www.advanced-ip-scanner ...

  6. Java多线程编程——进阶篇一

    一.线程栈模型与线程的变量 要理解线程调度的原理,以及线程执行过程,必须理解线程栈模型. 线程栈是指某一时刻内存中线程调度的栈信息,当前调用的方法总是位于栈顶.线程栈的内容是随着程序的运行动态变化的, ...

  7. jquery判断起止时间大小和非空

    //时间判断 function CheckDate() { var startTime = $('#txtTime').val(); //获取当前日期 var start = new Date(sta ...

  8. ScrollView和listview的冲突问题,关于宽度,和滑动

    只需要重新listview即可 package com.exmple.listscrow; import java.util.logging.LogManager; import android.co ...

  9. 【转】运行java -version命令时出现错误及解决

    转载地址:http://blog.sina.com.cn/s/blog_50f21fed01012sf2.html     按照上一篇的步骤配置JAVA_HOME.CLASSPATH和Path三个变量 ...

  10. CSS 高级语法 ---- 继承和选择器的分组

    1. 选择器的分组 —————————————————————————   可以对选择器进行分组,被分组的选择器享用共同的声明.   h1,h2,h3,h4,h5,h6 { color: green; ...