在 Safari 和其他阻止第三方 Cookie 的浏览器中处理 ITPHandle ITP in Safari and other browsers where third-party cookies are blocked

当今的许多浏览器都会阻止第三方 Cookie - 即发送到其他域(而不是浏览器地址栏中显示的域)的请求中包含的 Cookie。Many browsers today are blocking third-party cookies - cookies on requests to domains that are not the same as the one showing in the browser bar. 这会中断隐式流,并需要使用新的身份验证模式才能成功使用户登录。This breaks the implicit flow and requires new authentication patterns to successfully sign in users. 在 Microsoft 标识平台中,如果第三方 Cookie 已被阻止,我们会使用带有 PKCE 和刷新令牌的授权流使用户保持登录状态。In the Microsoft identity platform, we use the authorization flow with PKCE and refresh tokens to keep users signed in when third-party cookies are blocked.

什么是智能跟踪保护 (ITP)?What is Intelligent Tracking Protection (ITP)?

Apple Safari 提供默认已启用的隐私保护功能,称为智能跟踪保护 (ITP)。Apple Safari has an on-by-default privacy protection feature called Intelligent Tracking Protection, or ITP. ITP 会阻止“第三方”Cookie - 包含在跨域请求中的 Cookie。ITP blocks "third-party" cookies, cookies on requests that cross domains.

常见的用户跟踪形式是,在后台将一个 iframe 加载到第三方站点,并使用 Cookie 在整个 Internet 中关联用户。A common form of user tracking is done by loading an iframe to third-party site in the background and using cookies to correlate the user across the Internet. 遗憾的是,此模式也是单页应用 (SPA) 中实现隐式流的标准方式。Unfortunately, this pattern is also the standard way of implementing the implicit flow in single-page apps (SPAs). 当浏览器阻止第三方 Cookie 以阻止用户跟踪时,SPA 也会中断。When a browser blocks third-party cookies to prevent user tracking, SPAs are also broken.

并非只有 Safari 通过阻止第三方 Cookie 来增强用户隐私保护。Safari isn't alone in blocking third-party cookies to enhance user privacy. Brave 默认已阻止第三方 Cookie,而 Chromium(基于 Google Chrome 和 Microsoft Edge 的平台)也已宣布,今后会停止支持第三方 Cookie。Brave has blocked third-party cookies by default, and Chromium (the platform behind Google Chrome and Microsoft Edge) has announced that they as well will stop supporting third-party cookies in the future.

本文中所述的解决方法适用于所有这些浏览器或者任何阻止第三方 Cookie 的场合。The solution outlined in this article works in all of these browsers, or anywhere third-party cookies are blocked.

解决方法概述Overview of the solution

若要继续在 SPA 中对用户进行身份验证,应用开发人员必须使用授权代码流To continue authenticating users in SPAs, app developers must use the authorization code flow. 在授权代码流中,标识提供者会颁发一个代码,SPA 使用该代码兑换访问令牌和刷新令牌。In the auth code flow, the identity provider issues a code, and the SPA redeems the code for an access token and a refresh token. 当应用需要其他令牌时,可以使用刷新令牌流来获取新令牌。When the app requires additional tokens, it can use the refresh token flow to get new tokens. 适用于 SPA 的 Microsoft 标识平台库 MSAL.js 2.0 为 SPA 实现授权代码流,只需进行较小的更新,便可以直接替代 MSAL.js 1.x。MSAL.js 2.0, the Microsoft identity platform library for SPAs, implements the authorization code flow for SPAs and, with minor updates, is a drop-in replacement for MSAL.js 1.x.

对于 Microsoft 标识平台,SPA 和本机客户端遵循类似的协议指导:For the Microsoft identity platform, SPAs and native clients follow similar protocol guidance:

  • 使用 PKCE 代码质询Use of a PKCE code challenge
    • PKCE 是 Microsoft 标识平台上的 SPA 所必需的。PKCE is required for SPAs on the Microsoft identity platform. 建议对本机客户端和机密客户端使用 PKCE。PKCE is recommended for native and confidential clients.
  • 不使用客户端机密No use of a client secret

SPA 有两个额外的限制:SPAs have two additional restrictions:

SPA 应用的代码流

性能和 UX 影响Performance and UX implications

某些使用隐式流的应用程序会尝试通过 prompt=none 打开登录 iframe,在未重定向的情况下登录。Some applications using the implicit flow attempt sign-in without redirecting by opening a login iframe using prompt=none. 在大多数浏览器中,此请求会在响应中包含当前已登录用户的令牌(假设已被授予同意)。In most browsers, this request will respond with tokens for the currently signed-in user (assuming consent has already been granted). 此模式意味着应用程序无需提供完整页面重定向即可使用户登录,从而改善性能和用户体验 - 用户在访问网页时即已登录。This pattern meant applications did not need a full page redirect to sign the user in, improving performance and user experience - the user visits the web page and is signed in already. 由于在阻止了第三方 Cookie 的情况下,iframe 中的 prompt=none 不再是一个选项,因此应用程序必须访问顶级框架中的登录页才能让系统颁发授权代码。Because prompt=none in an iframe is no longer an option when third-party cookies are blocked, applications must visit the login page in a top-level frame to have an authorization code issued.

可通过两种方式完成登录:There are two ways of accomplishing sign-in:

  • 完整页面重定向Full page redirects
    • 首次加载 SPA 时,如果不存在任何会话(或者会话已过期),则会将用户重定向到登录页。On the first load of the SPA, redirect the user to the sign-in page if no session already exists (or if the session is expired). 用户的浏览器将访问登录页,提供包含用户会话的 Cookie,然后使用片段中的代码和令牌重定向回到应用程序。The user's browser will visit the login page, present the cookies containing the user session, and then redirect back to the application with the code and tokens in a fragment.
    • 重定向会导致 SPA 加载两次。The redirect does result in the SPA being loaded twice. 请遵循有关 SPA 缓存的最佳做法,以免应用完全下载两次。Follow best practices for caching of SPAs so that the app is not downloaded in-full twice.
    • 考虑在应用中包含预加载序列,以便在应用完全解包并执行 JavaScript 有效负载之前,查找登录会话并重定向到登录页。Consider having a pre-load sequence in the app that checks for a login session and redirects to the login page before the app fully unpacks and executes the JavaScript payload.
  • 弹出窗口Popups
    • 如果完整页面重定向的用户体验 (UX) 不适用于应用程序,请考虑使用弹出窗口来处理身份验证。If the user experience (UX) of a full page redirect doesn't work for the application, consider using a popup to handle authentication.
    • 当弹出窗口在身份验证后完成重定向到应用程序时,重定向处理程序中的代码将在本地存储中存储代码和令牌,供应用程序使用。When the popup finishes redirecting to the application after authentication, code in the redirect handler will store the code and tokens in local storage for the application to use. 与大多数库一样,MSAL.js 支持使用弹出窗口进行身份验证。MSAL.js supports popups for authentication, as do most libraries.
    • 浏览器正在逐渐削弱对弹出窗口的支持,因此弹出窗口不一定是最可靠的选项。Browsers are decreasing support for popups, so they may not be the most reliable option. 在创建弹出窗口之前可能需要用户与 SPA 交互,以满足浏览器的要求。User interaction with the SPA before creating the popup may be needed to satisfy browser requirements.

备注

Apple 将弹出窗口方法描述为一种临时兼容性修复方法,此方法旨在使原始窗口能够访问第三方 Cookie。Apple describes a popup method as a temporary compatibility fix to give the original window access to third-party cookies. 尽管 Apple 将来可能会去除这种权限转移,但这不会影响本文中的指导。While Apple may remove this transferral of permissions in the future, it will not impact the guidance here. 此处,弹出窗口用作登录页的第一方导航,以便会话可被找到且授权代码可被提供。Here, the popup is being used as a first party navigation to the login page so that a session is found and an auth code can be provided. 将来应该也会继续使用这种方式。This should continue working into the future.

有关 iframe 应用的说明A note on iframe apps

Web 应用中的一种常见模式是使用 iframe 将一个应用嵌入到另一个应用。A common pattern in web apps is to use an iframe to embed one app inside another. 顶级框架处理用户身份验证,iframe 中托管的应用程序可以相信用户已登录,并使用隐式流以无提示方式提取令牌。The top-level frame handles authenticating the user, and the application hosted in the iframe can trust that the user is signed in, fetching tokens silently using the implicit flow. 当第三方 Cookie 被阻止时,无提示令牌获取方式将不再起作用 - 在 iframe 中嵌入的应用程序必须改用弹出窗口来访问用户的会话,因为它无法导航到登录页。Silent token acquisition no longer works when third-party cookies are blocked - the application embedded in the iframe must switch to using popups to access the user's session as it can't navigate to the login page.

浏览器中的刷新令牌的安全影响Security implications of refresh tokens in the browser

向浏览器颁发刷新令牌被认为是一个安全问题。Issuing refresh tokens to the browser is considered a security issue. 跨站点脚本 (XSS) 攻击或已遭入侵的 JS 包可能会盗取并在远程使用刷新令牌,直到该令牌过期或吊销。Cross-site scripting (XSS) attacks or compromised JS packages can steal the refresh token and use it remotely until it expires or is revoked. 为了最大程度地降低刷新令牌被盗的风险,将为 SPA 颁发有效期仅为 24 小时的令牌。In order to minimize the risk of stolen refresh tokens, SPAs will be issued tokens valid for only 24 hours. 24 小时后,应用必须通过顶级框架访问登录页,以获取新的授权代码。After 24 hours, the app must acquire a new authorization code via a top-level frame visit to the login page.

选择这种生存期受限的刷新令牌模式是为了在安全性与 UX 降级之间实现平衡。This limited-lifetime refresh token pattern was chosen as a balance between security and degraded UX. 如果不使用刷新令牌或第三方 Cookie,在需要新令牌或其他令牌时,授权代码流(根据 OAuth 安全最佳做法当前草案中的建议)会变得很繁琐。Without refresh tokens or third-party cookies, the authorization code flow (as recommended by the OAuth security best current practices draft) becomes onerous when new or additional tokens are required. 每当令牌过期时(对于 Microsoft 标识平台令牌,通常每隔一小时就会过期),都需要为获取一个令牌而执行完整页面重定向或显示弹出窗口。A full page redirect or popup is needed for every single token, every time a token expires (every hour usually, for Microsoft identity platform tokens).

后续步骤Next steps

详细了解授权代码流Learn more about the authorization code flow.