繁体   English   中英

IE8 - IE10跨域JSONP cookie令人头疼

[英]IE8 - IE10 cross domain JSONP cookie headache

由于完全不受我控制的决定,我处于以下情况:

  • 我在catalog.org上有一个产品列表

  • 单击产品上的“添加到购物车”按钮会向Secure.com/product/add/[productKey发出AJAX JSONP请求,这会将购物车记录保存到数据库, 使用购物车ID设置cookie ,然后返回true响应(如果失败则为false)

  • 回到catalog.org,如果响应为真,则向secure.com/cart/info发出另一个AJAX JSONP请求, 请求读取购物车ID cookie ,获取记录,并返回购物车中的商品数量

  • 再次返回catalog.org,读取响应并更新页面上的元素,显示购物车中的商品数量(如果有)

  • 此时,单击catalog.org上的“转到购物车”按钮会在secure.com上显示购物车摘要

这在Firefox 17,Chrome 32和IE 11中运行良好。它也适用于我们开发和测试环境中的IE8 - IE10,其中catalog.org是catalog.development.com,catalog.test.com和secure.com是安全的。 development.com和secure.test.com分别。

但是,在我们部署到生产之后,这停止了在IE8 - IE10中工作。 将产品添加到购物车后,购物车中的商品数量会在catalog.org上成功更新。 然后,在单击catalog.org上的“转到购物车”按钮后,secure.com上的购物车摘要显示任何内容,因为它无法读取cookie。 在IE开发人员工具中进入缓存>“查看cookie信息”显示没有购物车ID cookie。 它应该存在,就像在其他浏览器和我们的开发和测试环境中一样。

我相信正在发生的事情是IE阻止第三方cookie。 我们已经为secure.com上的所有请求添加了一个P3P精简策略标头,但cookie仍未设置。 我们设置的标题是:

P3P: CP="CAO PSA OUR"

为什么不在IE8-IE10中添加紧凑的策略头修复此问题? 我怎样才能解决这个问题,以便在IE的所有版本中运行?

下面有几个好主意。 我接受了@ sdecima's,因为它听起来最有希望。 我们最终结合了其中的一些想法,但设法避免了XDomainRequest:

  • 单击产品上的“添加到购物车”按钮会向Secure.com/product/add/[productKey发出AJAX JSONP请求,这会将购物车记录保存到数据库, 使用购物车ID设置cookie ,然后返回true响应(如果失败则为false)

我们在secure.com/product/add上更改了操作,以返回一个JSON对象,其中包含指示成功或失败的布尔值以及购物车ID。

  • 回到catalog.org,如果响应为真,则向secure.com/cart/info发出另一个AJAX JSONP请求, 请求读取购物车ID cookie ,获取记录,并返回购物车中的商品数量

我们更改了回调函数以检查响应对象中的两个属性。 如果成功,并且存在购物车ID,我们会在页面上创建隐藏的iframe。 iframe的src属性设置为我们添加到secure.com的新端点。 此操作接受购物车ID参数并保存购物车ID Cookie。 我们不再需要在secure.com/product/add操作中保存cookie。

接下来,我们更改了secure.com/cart/info上的操作以接受购物车ID参数。 此操作将使用购物车ID参数(如果存在)来获取购物车信息,否则它仍将尝试读取cookie。 如果我们可以保证iframe已经完成加载并且cookie已经保存在secure.com上,那么这个额外的检查将是不必要的,但是由于浏览器安全限制,我们无法知道iframe何时在catalog.org上完成加载。

最后,仍然需要P3P标题CP="CAO PSA OUR"才能在IE7-IE10中工作。 (是的,这也适用于IE7 :)

我们现在有一个解决方案(尽管是一个非常复杂的解决方案),用于保存和访问适用于所有主流浏览器的跨域cookie,至少在我们能够可靠测试的时候。

我们可能会对此进行一些重构。 首先,此时对secure.com/cart/info的第二个AJAX JSONP请求是多余的,因为我们可以将原始请求中所需的所有信息返回到secure.com/product/add操作(更改的附带好处)该操作返回一个JSON对象 - 加上我们可以返回一条错误消息,指出如果出现错误则确切失败的原因)。

简而言之

Cookie不会在IE 8和9上通过跨源请求。但它应该适用于IE 10和11。


IE 8和9

在IE8 / 9上, XMLHttpRequest部分支持CORS ,并且在XDomainRequest对象的帮助下进行跨源请求,该对象不向每个请求发送cookie。

您可以在以下官方MSDN博客文章中阅读有关此内容的更多信息:
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

特别是这部分:

5。 不会随请求一起发送身份验证或Cookie

为了防止滥用用户的环境权限(例如cookie,HTTP凭证,客户端证书等), 请求将被剥离cookie和凭据,并将忽略HTTP响应中的任何身份验证质询或Set-Cookie指令 XDomainRequests不会在以前经过身份验证的连接上发送,因为某些Windows身份验证协议(例如NTLM / Kerberos)是基于每个连接而不是基于请求的。

IE 10+

从IE10开始, XMLHTTPRequest中添加了完整的CORS支持,它应该可以正常使用来自服务器的响应的正确的Access-Control-Allow-Origin标头属性(希望在浏览器上设置cookie)。

更多相关信息:
http://blogs.msdn.com/b/ie/archive/2012/02/09/cors-for-xhr-in-ie10.aspx
和这里:
http://www.html5rocks.com/en/tutorials/cors/

IE 8和9的变通方法

在IE8 / 9上解决这个问题的唯一方法是引用与上面相同的MSDN帖子

希望对跨源请求执行用户身份验证的站点可以使用显式方法(例如POST正文或URL中的令牌)来传递此身份验证信息,而不会冒用户的环境权限。

结论:第三方cookie通常被隐私/广告拦截扩展程序阻止,应被视为不可靠。 你会在脚下射击,让它继续生产。

语法表明端点有一天会成为RESTful的野心。 唯一的问题是使用cookie,它会将整个“无状态”概念抛到窗外! 理想情况下,应对API进行更改。 如果您没有与第三方集成(即“secure.com”由您的公司运营),这绝对是处理该问题的正确方法。

cartIdsecure.com cookie移到其查询字符串中:

secure.com/product/add/9876?cartId=1234    //should be a POST

从哪里获得有效的cartId值? 我们可以将其保留在目录域的一些secure-com-cart-id cookie集中,这将避免任何跨域问题。 检查该值,如果存在,则附加到每个secure.com请求,如上所述:

$.post('secure.com/product/add/9876', {    //needs jQuery.cookie
  cartId: $.cookie('secure-com-cart-id')
});

如果您没有有效的cartId ,请将其视为新用户,并在没有参数的情况下发出请求。 然后,您的API应分配一个新ID并在响应中返回它。 然后可以更新“本地” secure-com-cart-id cookie。 冲洗并重复。

瞧,你刚刚持有一个活跃的用户购物车而没有用cookie来污染API调用。 对你的建筑师大喊大叫。 如果你不能这样做(改变API语法或大喊大叫),你将不得不建立一个到secure.com端点的隧道,这样就不会有跨域请求 - 基本上就是在catalog.org/secure- com-endpoint将把请求逐字地传递secure.com 这是一种专门用于避免对API进行更改的解决方法,只是不要使用代码并设置适当的Apache / IIS / F5规则来代替它。 快速搜索提出了几个解释, 这个看起来对我很好。

PS:在我看来,这是一个经典的XY问题 解决方案不一定是关于持久存在第三方cookie,而是将必要参数传递给第三方,同时将数据保存在某处

虽然正确的解决方案是改变架构,但如果您正在寻找一种快速,临时的解决方案:

JSONP文件实际上只是javascript。 您可以添加一行代码以将Cookie设置到JSONP的前面。

例如,而不是:

callback({"exampleKey": "exampleValue"});

您的JSONP可能如下所示:

document.cookie="cartID=1234";
callback({"exampleKey": "exampleValue"});

如果您控制DNS记录,请创建一个新条目,以便两个服务器位于同一个域中。

是否有1个数据库服务于catalog.org和secure.com,还是可以进行通信?

如果是这样的话,你就明白了。

当catalog.org服务器cookie时,将其保存在db中。 当secure.com服务器cookie时,将其保存在db中。 然后,您可以确定哪个购物车属于哪个用户。

这是一个值得考虑的有趣问题......更新2:

当用户访问catalog.org时:

  • 检查他是否有cat_org cookie,如果没有,则:

    • 在catalog.org中:

      • 创建一个键值对并保存在db {cat_cookie_id,unique_number}中
      • 在浏览器中设置cat_cookie_id
      • 指示浏览器访问ajax访问secure.com/register/unique_number
    • 在secure.com

      • 从url读取unique_number
      • 创建secure_cookie id
      • 保存在db {cat_cookie_id,unique_number,secure_cookie_id}中
      • 删除unique_number,因为这是一次性使用密钥

现在,db可以将cat_cookie_id映射到secure_cookie_id,反之亦然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM