And*_*rew 15 javascript cookies safari fetch cors
Set-Cookie
在使用Fetch API时(实际上,通过fetch polyfill),我无法让Safari成功应用服务器响应.相同的代码在FF和Chrome中正常工作(我使用native和polyfill进行了测试fetch
).
credentials: true
;Set-Cookie
标题响应;有人知道问题可能是什么吗?
我已经阅读了文档,并浏览了许多已关闭的错误报告.除非我遗漏了一些东西,否则我认为问题可能是"默认浏览器行为"处理cookie和CORS - 而不是fetch(通过polyfill源代码阅读,它似乎100%无知cookie).一些错误报告表明,格式错误的服务器响应可能会阻止cookie被保存.
我的代码看起来像这样:
function buildFetch(url, init={}) {
let headers = Object.assign({}, init.headers || {}, {'Content-Type': 'application/json'});
let params = Object.assign({}, init, { credentials: 'include', headers });
return fetch(`${baseUrl}${url}`, params);
}
buildFetch('/remote/connect', {method: 'PUT', body: JSON.stringify({ code })})
.then(response => response.json())
.then(/* complete authentication */)
Run Code Online (Sandbox Code Playgroud)
实际的授权请求如下.我正在使用cURL来获取确切的请求/响应数据,因为Safari很难复制/粘贴它.
curl 'https://mydevserver:8443/api/v1/remote/connect' \
-v \
-XPUT \
-H 'Content-Type: application/json' \
-H 'Referer: http://localhost:3002/' \
-H 'Origin: http://localhost:3002' \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8' \
--data-binary '{"token":"value"}'
* Trying 127.0.0.1...
* Connected to mydevserver (127.0.0.1) port 8443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
* Server certificate: mydevserver
> PUT /api/v1/remote/connect HTTP/1.1
> Host: mydevserver:8443
> Accept: */*
> Content-Type: application/json
> Referer: http://localhost:3002/
> Origin: http://localhost:3002
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8
> Content-Length: 15
>
* upload completely sent off: 15 out of 15 bytes
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: http://localhost:3002
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Api-Key, Device-Key
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Expose-Headers: Date
< Content-Type: application/json; charset=utf-8
< Content-Length: 37
< Set-Cookie: express:sess=[SESSIONKEY]=; path=/; expires=Fri, 17 Feb 2017 15:30:01 GMT; secure; httponly
< Set-Cookie: express:sess.sig=[SIGNATURE]; path=/; expires=Fri, 17 Feb 2017 15:30:01 GMT; secure; httponly
< Date: Fri, 17 Feb 2017 14:30:01 GMT
< Connection: keep-alive
<
* Connection #0 to host mydevserver left intact
{"some":"normal","response":"payload"}
Run Code Online (Sandbox Code Playgroud)
And*_*rew 17
回答我自己的问题.
虽然我了解他们的动机,但我觉得这是Safari的"按预期工作"的行为,这令人非常恼火.XHR(当它本地登陆时可能是原生取件)根本不支持第三方cookie的设置.这种失败是完全透明的,因为它是由脚本环境之外的浏览器处理的,因此基于客户端的解决方案实际上是不可能的.
您可以在此处找到一个推荐的解决方案,即在API服务器上的HTML页面上打开一个窗口或iframe,并在那里设置一个cookie.此时,第三方cookie将开始工作.这非常难看,并且无法保证Safari在某些时候不会关闭这个漏洞.
我的解决方案是基本上重新实现会话cookie执行的身份验证系统.即:
X-Auth: [token]
其中[token]
是一个非常小的,短命的JWT,其中包含您的会话所需的信息(理想情况下只有用户ID - 在应用程序的生命周期内不太可能发生变异的东西 - 但绝对不是如果权限可以在会话期间更改);X-Auth
到Access-Control-Allow-Headers
;X-Token
响应头并在X-Token
它看到它时将其作为请求头回显(您可以通过使用本地存储来实现持久性 - 令牌过期,因此即使值存在多年,它也不能在某一点之后被赎回);请注意,JWT(或任何类似的)旨在解决一个完全不同的问题,并且由于"重放"问题,应该永远不会用于会话管理(想想如果用户打开两个带有自己的头状态的窗口会发生什么情况).但是,在这种情况下,它们提供了您通常需要的瞬间和安全性.最重要的是,你应该在支持它们的浏览器上使用cookie,保持会话信息尽可能小,保持你的JWT尽可能短,并构建你的服务器应用程序,以期待意外和恶意重播攻击.
仅供参考,尝试此〜18个月后,此解决方案对我不起作用。或者,对于某些用户而言,它似乎是断断续续的,这确实很奇怪。
一个推荐的解决方案是在API服务器上打开一个窗口或iframe到HTML页面并在其中设置cookie。此时,第三方Cookie将开始起作用。这是非常丑陋的,并且不能保证Safari不会在某个时候消除漏洞。
最好的猜测是Safari内部使用的逻辑取决于您设法获取Cookie的顺序,或者更复杂,更不透明的事物。
我最终选择的解决方案是使用DNS,这可能是一个选择,因为您要从不同于API的主机提供React App,或者以其他方式控制两个站点
我们的客户来自www.company-name.com,而我们的API位于company-name.herokuapp.com。通过将CNAME记录为api .company-name.com-> company-name.herokuapp.com,并使用同一域的子域来处理客户端对API的请求,Safari停止了将其视为“第三方“ 曲奇饼。
好处是涉及的代码很少,而且全部都使用了完善的东西...缺点是,如果要使用https,则需要对API主机进行一些控制/所有权-它们需要有效的证书客户端域,否则用户将收到证书警告-因此,如果所涉及的API不是您的或合作伙伴的API,则此操作将不起作用(至少对于面向最终用户的操作无效)。
归档时间: |
|
查看次数: |
5310 次 |
最近记录: |