Safari禁止第三方Cookie无法获取用户登录状态
# 问题描述
在跨站(cross-site)情况下, 苹果Safari浏览器无法获取竹云IDaaS的用户登录状态接口(https://{domain_name}/api/v1/config/isLogin),而在Windows、安卓系统的浏览器上可以获取到用户的登录状态。
# 问题分析
目前各大浏览器厂商为了保护用户隐私,不断加强浏览器的安全限制。苹果Safari采用更加保守的Cookie安全策略,并默认开启“阻止跨网站跟踪”,禁止跨站访问第三方Cookie,而其它浏览器厂商后续也会陆续跟进限制,当前看只是时间问题。 Safari这个配置不影响直接使用统一登录页面集成的业务应用系统,但是对业务系统直接通过API调用IDaaS获取用户状态会有影响,因为Safari阻止IDaaS SSO Cookie跨站提交,造成调用获取用户状态接口永远返回未登录状态(fasle)。
# 解决方案
站在safari浏览器角度来看, 只要是涉及第三方站点cookie一律禁止。临时解决方案可以通知用户手工关闭“阻止跨网站跟踪”,但是对于用户的体验不佳。解决的问题根本在于如何将第三方(third party cookie)变成第一方(first party cookie),应用系统调用竹云IDaaS接口请求变成同站(same site)之间的接口访问,这样就不会触发浏览器的阻止第三方cookie规则。
例如,IDaaS默认分配给企业客户的域名是companyname.bccastle.com,应用系统的域名是app.companyname.com,通过IDaaS提供的自定义企业域名功能,将IDaaS的默认域名变成一个企业自身的域名地址,如login.companyname.com。
login.companyname.com #企业自定义域名后的IDaaS服务
app.companyname.com #应用系统的域名
2
⚠️浏览器的安全策略也在不断的变化,若干时间后文中所述内容可能不再适用
# 相关知识
涉及到前端技术时,同源(Same-Origin)和同站(Same-Site)是经常遇到的术语。
# 同源(Same Origin)
同源(origin)= 协议(scheme)+ 主机名(hostname)+ 端口号(port)
当一个请求url的协议、域名、端口三者之间的任意一个与当前页面url不同即为跨源或跨域。 也就是说违反同源策略即为跨源或跨域(cross origin)
# 同站(Same Site)
Cookie的校验较宽松,Cookie只关注域名,忽略协议和端口,只要两个 URL 的 eTLD+1 相同即可,eTLD 表示有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,例如,.com、.co、.uk、.github.io 等。而 eTLD+1 则表示,有效顶级域名+二级域名,例如taobao.com等。 如:
www.taobao.com 和 www.baidu.com 是跨站, www.a.taobao.com 和 www.b.taobao.com 是同站 a.github.io和b.github.io是跨站
总结跨站如下
- 两个URL顶级域名和二级域名不同就是跨站(也称第三方(Third-party)),跨站一定跨域,反之不成立。
- 相同则是同站第一方(First-party)。
# 各场景总结
同源时:cookie会自动读取与存储、发送
跨域未跨站(同站)时:后端添加CORS响应头保证跨域请求正常,配合前端XHR.withCredentials=true即可正常发送cookie。
跨域且跨站时(跨站一定跨域):添加SameSite=none;Secure(注意:即使设置 SameSite=None 后,Safari 也不发送 cookie,而其它浏览器目前暂时支持发送cookie);
或者使用nginx反向代理,将跨站请求变成同站来解决cookie跨站问题。
另,网络上可能存在其它的workaround解决方案,但是随着浏览器厂商的不断加强安全限制,可能引起未知的兼容问题,需要应用开发者权衡利弊,三思而行。