如何在浏览器中处理第三方 Cookie 阻止

许多浏览器都会阻止第三方 Cookie,即针对浏览器地址栏中所显示域以外的域的请求的 Cookie。 这些 Cookie 也称为“跨域 Cookie”。 此块会中断隐式流,并需要使用新的身份验证模式才能成功使用户登录。 在 Microsoft 标识平台中,如果第三方 Cookie 已被阻止,我们会使用带有用于代码交换的证明密钥 (PKCE) 和刷新令牌的授权代码流使用户保持登录状态。 建议使用这种带有 Proof Key for Code Exchange 方法的授权代码流,而不是隐式流。

什么是智能跟踪保护 (ITP) 和隐私沙盒?

Apple Safari 提供默认已启用的隐私保护功能,称为智能跟踪保护 (ITP)。 Chrome 有一个名为隐私沙盒的浏览器隐私计划。 这些计划包括浏览器在隐私保护方面的许多不同做法,并具有不同的时间线。 这两项工作都阻止跨域请求上的“第三方”Cookie,默认情况下 Safari 和 Brave 会阻止第三方 Cookie。 Chrome 最近宣布,默认情况下,他们将开始阻止第三方 Cookie。 隐私沙盒包括对分区存储以及第三方 Cookie 阻止的更改。

常见的用户跟踪形式是,在后台将一个 iframe 加载到第三方站点,并使用 Cookie 在整个 Internet 中关联用户。 遗憾的是,此模式也是单页应用 (SPA) 中实现隐式流的标准方式。 阻止第三方 Cookie 保护用户隐私的浏览器还可以阻止 SPA 的功能。 由于阻止第三方 Cookie 及其相关的安全风险,不再建议在 SPA 中使用隐式流。

本文中所述的解决方法适用于所有这些浏览器或者任何阻止第三方 Cookie 的场合。

解决方法概述

若要继续在 SPA 中对用户进行身份验证,应用开发人员必须使用授权代码流。 在授权代码流中,标识提供者会颁发一个代码,SPA 使用该代码兑换访问令牌和刷新令牌。 当应用需要新令牌时,它可以使用刷新令牌流来获取新令牌。 适用于 JavaScript v2.0 及更高版本的 Microsoft 身份验证库 (MSAL) 为 SPA 实现授权代码流,只需进行较小的更新,便可以直接替代 MSAL.js 1.x。 请参阅迁移指南,了解如何将 SPA 从隐式迁移到身份验证代码流。

对于 Microsoft 标识平台,SPA 和本机客户端遵循类似的协议指导:

  • 使用 PKCE 代码质询
    • PKCE 是 Microsoft 标识平台上的 SPA 所必需的。 建议对本机客户端和机密客户端使用 PKCE。
  • 不使用客户端机密

SPA 还有两个限制:

显示单页应用和安全令牌服务终结点之间的 OAuth 2 授权代码流的图表。

性能和 UX 影响

某些使用隐式流的应用程序会尝试通过 prompt=none 打开登录 iframe,在未重定向的情况下登录。 在大多数浏览器中,此请求在响应中包含当前已登录用户的令牌(假设已授予同意)。 此模式意味着应用程序无需提供完整页面重定向即可使用户登录,从而改善性能和用户体验 - 用户在访问网页时即已登录。 由于在阻止了第三方 Cookie 的情况下,iframe 中的 prompt=none 不再是一个选项,因此应用程序必须调整其登录模式才能让系统颁发授权代码。

在不使用第三方 Cookie 的情况下,可通过两种方式完成登录:

  • 完整页面重定向
    • 首次加载 SPA 时,如果不存在任何会话(或者会话已过期),则会将用户重定向到登录页。 用户的浏览器访问登录页,提供包含用户会话的 Cookie,然后使用片段中的代码和令牌重定向回到应用程序。
    • 重定向会导致 SPA 加载两次。 请遵循有关 SPA 缓存的最佳做法,以免应用完全下载两次。
    • 考虑在应用中包含预加载序列,以便在应用完全解包并执行 JavaScript 有效负载之前,查找登录会话并重定向到登录页。
  • 弹出窗口
    • 如果完整页面重定向的用户体验 (UX) 不适用于应用程序,请考虑使用弹出窗口来处理身份验证。
    • 当弹出窗口在身份验证后完成重定向到应用程序时,重定向处理程序中的代码将在本地存储中存储身份验证代码和令牌,供应用程序使用。 与大多数库一样,MSAL.js 支持使用弹出窗口进行身份验证。
    • 浏览器正在逐渐削弱对弹出窗口的支持,因此弹出窗口不一定是最可靠的选项。 在创建弹出窗口之前可能需要用户与 SPA 交互,以满足浏览器的要求。

Apple 将弹出窗口方法描述为一种临时兼容性修复方法,此方法旨在使原始窗口能够访问第三方 Cookie。 尽管 Apple 将来可能会去除这种权限转移,但这不会影响本文中的指导。

此处,弹出窗口用作登录页的第一方导航,以便会话可被找到且授权代码可被提供。 将来应该也会继续使用这种方式。

在阻止第三方 Cookie 的情况下,开发者可以继续使用 prompt=none,不过会更多地看到 interacion_required 错误提示。 如果出现无提示令牌获取期间失败,建议始终交互式方法回退

使用 iframe

Web 应用中的一种常见模式是使用 iframe 将一个应用嵌入到另一个应用内:上层框架处理用户身份验证,并且 iframe 中托管的应用程序可以识别用户已登录,使用隐式流以静默方式获取令牌。 但是,无论浏览器中是启用还是阻止了第三方 Cookie,这一假设都有几点注意事项。

当第三方 Cookie 被阻止时,无提示令牌获取方式将不再起作用 - 在 iframe 中嵌入的应用程序必须改用弹出窗口来访问用户的会话,因为它无法导航到嵌入式帧内的登录页。

可以通过同源和跨域 JavaScript 脚本 API 访问在使用 iframe 嵌入的应用与父应用之间实现单一登录,但需要将用户(帐户)提示从父应用传递到使用 iframe 嵌入的应用。 有关详细信息,请参阅 GitHub 上 MSAL.js 存储库中的在使用 iframe 嵌入的应用中使用 MSAL.js

浏览器中的刷新令牌的安全影响

跨站点脚本 (XSS) 攻击或已遭入侵的 JS 包可能会盗取并在远程使用刷新令牌,直到该令牌过期或吊销。 应用程序开发者有责任降低应用程序跨站点脚本的风险。 为了最大程度地降低刷新令牌被盗的风险,将为 SPA 颁发有效期仅为 24 小时的令牌。 24 小时后,应用必须通过顶级框架访问登录页,以获取新的授权代码。

选择这种生存期受限的刷新令牌模式是为了在安全性与 UX 降级之间实现平衡。 如果不使用刷新令牌或第三方 Cookie,在需要新令牌或其他令牌时,授权代码流(根据 OAuth 安全最佳做法当前草案中的建议)会变得很繁琐。 每当令牌过期时(对于 Microsoft 标识平台令牌,通常每隔一小时就会过期),都需要为获取一个令牌而执行完整页面重定向或显示弹出窗口。

用户类型特定的缓解措施

第三方 Cookie 对于用户和应用程序的影响程度不尽相同。 某些情况下,由于体系结构或设备管理,无需第三方 Cookie 即可无提示调用续订令牌。

对于托管企业设备场景,某些浏览器和平台组合支持设备条件访问。 应用设备标识可最大程度地减少对第三方 Cookie 的需求,因为身份验证状态可能来自设备而不是浏览器。

对于 Azure AD B2C 应用程序场景,客户可以设置自定义登录域以匹配应用程序的域。 在此场景中,浏览器不会阻止第三方 Cookie,因为 Cookie 保留在同一域中(例如 login.contoso.comapp.contoso.com)。

在不使用第三方 Cookie 的情况下,对 Front-Channel 注销的限制

从 SPA 注销用户时,MSAL.js 建议使用弹出窗口或重定向注销方法。 虽然这会清除服务器和浏览器存储中的身份验证会话,但存在无法访问第三方 Cookie 的风险,并非所有联合应用程序都会同时看到注销。 这是 OpenID Front-Channel Logout 1.0 规范的已知限制。 这对用户的意义在于,同一用户其他应用程序的现有访问令牌在过期前将继续有效。 用户可以在标签页 A 中注销应用程序 A,但在标签页 B 中的应用程序 B 在访问令牌的剩余有效时间内仍将显示为登录状态。 当应用程序 B 的令牌过期并调用服务器以获取新令牌时,应用程序 B 将收到来自服务器响应,指出此会话已过期,并提示用户进行身份验证。

Microsoft 的注销页面和 Internet 隐私最佳做法建议用户在注销应用程序后关闭所有浏览器窗口。

后续步骤

有关授权代码流和 MSAL.js 的详细信息,请参阅: