w3c/webappsec-dbsc
GitHub: w3c/webappsec-dbsc
该项目提出了一种 Web 安全协议,通过将会话凭证绑定到设备硬件来防御 Cookie 盗窃,从而有效防止账户劫持。
Stars: 451 | Forks: 44
# Device Bound Session Credentials 说明
这是 Device Bound Session Credentials 的代码仓库。欢迎
[贡献](CONTRIBUTING.md)!
## 作者:
- [Kristian Monsen](kristianm@google.com), Google
- [Arnar Birgisson](arnarb@google.com), Google
## 参与方式(即将推出)
- [Issue 追踪器](https://github.com/WICG/dbsc/issues)
- [讨论区]
## 目录
- [简介](#introduction)
- [目标](#goals)
- [非目标](#non-goals)
- [Device Bound Session Credentials 的不同之处](#what-makes-device-bound-session-credentials-different)
- [应用级绑定](#application-level-binding)
- [浏览器发起的刷新](#browser-initiated-refreshes)
- [TPM 考量](#tpm-considerations)
- [隐私考量](#privacy-considerations)
- [企业支持](#enterprise-support)
- [高层概述](#high-level-overview)
- [启动会话](#start-session)
- [会话注册 Header](#session-registration-header)
- [会话注册 JWT](#session-registration-jwt)
- [会话注册指令 JSON](#session-registration-instructions-json)
- [维护会话](#maintaining-a-session)
- [刷新流程](#refresh-procedure)
- [结束会话](#ending-a-session)
- [与其他 API 的交互](#interactions-with-other-apis)
- [Login Status API](#login-status-api)
- [与非活动文档的交互(BFCache, Prerendering)](#interaction-with-inactive-documents-bfcache-prerendering)
- [StartSession 的替代 JavaScript API](#alternative-javascript-api-for-startsession)
## 简介
Device Bound Session Credentials (DBSC) 旨在减少由 Cookie 盗取导致的账户劫持。它通过引入一种协议和浏览器基础设施来维护并证明持有加密密钥来实现这一目标。将 Cookie 作为身份验证机制的主要挑战在于,它们仅适用于不记名令牌(bearer-token)方案。在桌面操作系统上,应用程序隔离不足,本地恶意软件通常可以访问浏览器本身可以访问的任何内容,而浏览器必须能够访问 Cookie。另一方面,使用私钥进行身份验证允许利用系统级保护来防止密钥泄露。
DBSC 为网站提供了一个 API,以便在会话抽象之后控制此类密钥的生命周期,并提供了一个协议用于定期且自动向网站服务器证明持有这些密钥。每个会话都有一个单独的密钥,并且应该无法检测出两个不同的会话密钥是否来自同一台设备。主要目标之一是能够与当前常见类型的身份验证基础设施进行轻松集成。通过将私钥绑定到设备并在适当的时间间隔进行证明,浏览器可以限制恶意软件将滥用行为从用户设备上卸载的能力,从而显著提高浏览器或服务器检测和缓解 Cookie 盗窃的机会。
DBSC 通过加密密钥绑定到设备,这些密钥在正常情况下无法从用户的设备导出,这在本文档的其余部分称为设备绑定。DBSC 提供了一个 API,服务器可以使用它来创建绑定到设备的会话,并且该会话可以定期刷新,并附带可选的加密证明,证明该会话仍绑定到原始设备。在登录时,该 API 会通知浏览器会话已启动,从而触发密钥创建。然后它指示浏览器,只要在该会话处于活动状态时发出请求,浏览器就应确保存在特定的 Cookie。如果这些 Cookie 不存在,DBSC 将在查询配置的端点以获取更新的 Cookie 时暂停网络请求。
### 目标
通过提供长期存在的 Cookie 不记名令牌的替代方案来减少会话盗窃,该方案允许绑定到用户设备的会话身份验证。这使得互联网对用户来说更安全,因为他们的身份被滥用的可能性降低了,因为恶意软件被迫在本地行动,因此变得更容易检测和缓解。同时,目标是破坏 Cookie 盗窃生态系统并迫使其适应新的保护措施。
DBSC 的主要威胁模型是攻击者能够读取和篡改用户代理,例如通过被恶意软件入侵的浏览器,其中恶意软件可以读取和修改浏览器内存和存储在磁盘上的机密信息。在许多操作系统中,恶意软件可能能够获得特权(root、kernel 等)访问。DBSC 旨在通过建立一种加密协议来解决这一威胁,在该协议中,机密信息可以存储在专用系统(如安全飞地)中,尽管 DBSC 并未指定实现者应如何存储、备份或同步密钥,只要此类存储能够抵御上述威胁即可。
作为次要考虑,DBSC 还可以缓解某些类型的网络和服务器入侵,例如网络攻击者拦截(其中攻击者可以读取或修改网络流量)或 HTTP 服务器日志泄露(其中服务器错误地将完整的 HTTP 请求/响应 header 记录到可以被非特权内部人员读取的日志中)。
在所有这些场景中,DBSC 旨在执行特定约束,即*对用户代理或网络流量的临时读/写访问不能启用来对任何已建立的 DBSC 会话的长期访问*。例如,如果攻击者在受害者浏览器进程中运行恶意软件,一旦该恶意软件被移除,他们应该无法继续作为受害者浏览器进行身份验证。(但是,请注意,“长期”的定义取决于配置的刷新周期;在该周期内,攻击者*可能*继续对任何已建立的会话拥有短期访问权限。)
### 非目标
当攻击者持续访问受损的用户代理时,DBSC 将不会阻止对任何浏览器会话的临时访问。拥有对受损用户代理(或网络 AitM 等)持续访问权限的攻击者将能够持续访问新的 DBSC 控制的不记名令牌,并且在许多现代操作系统上,在受损设备上运行恶意软件的攻击者将能够甚至将安全元素视为签名预言机,以提供 DBSC 密钥的持有证明。
### 考虑过的替代方案
DBSC 并不是该领域的第一个提案,其中著名的还有 [Token Binding](https://en.wikipedia.org/wiki/Token_Binding) 和 [WebCrypto](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API)。本提案提供了两个重要功能,我们认为这使得它比之前的提案更容易部署。DBSC 提供了应用级绑定和浏览器发起的刷新,可以确保设备仍绑定到原始设备。
#### 应用级绑定
对于网站而言,设备绑定对于保护用户的已验证会话最有用。DBSC 允许网站将绑定会话的设置与用户登录机制紧密耦合,使会话和密钥的生命周期变得明确且可控,并允许服务器设计基础设施,将会话凭据的验证放置在基础设施中处理用户凭据的位置附近。
像 Token Binding 这样的替代方案通过例如与 TLS 集成获益良多,但这可能会使集成变得更困难,例如在 TLS 通道终止距离用户登录和会话管理背后的应用程序逻辑很远的环境中。
#### 浏览器发起的刷新
其他提案已经探索了更底层的 API,供网站创建和使用受保护的私钥,例如通过 WebCrypto 或类似于 WebAuthn 的 API。虽然这在理论上可行,但它给网站集成带来了非常大的负担。特别是,由于使用受保护密钥的成本很高,网站必须设计一些基础设施以便仅按需收集签名。
这意味着要么是高接触集成,其中密钥仅用于保护敏感操作(如进行购买),要么是将任意请求重定向到某个端点的一般能力,该端点收集并验证签名,然后重试原始请求。前者不能保护整个会话,并且违反了默认安全的原则,而后者对于由多个团队的多个组件构建的大型网站来说可能成本过高,并且可能需要对 Web 和 RPC 框架进行重大重写。
DBSC 反而允许网站将会话绑定整合到几个点:在登录时,它通知浏览器会话启动,从而触发密钥创建。然后它指示浏览器,只要在该会话处于活动状态时发出请求,浏览器就应确保存在特定的 Cookie。浏览器通过在需要此类 Cookie 时调用专用的刷新端点(由网站指定)来实现这一点,向该端点出示私钥的持有证明。该端点随后使用现有的标准 Set-Cookie header 向浏览器提供发出其他请求所需的短期 Cookie。
这提供了两个重要的好处:
1. 会话绑定逻辑整合在登录机制和新的专用刷新端点中。网站的所有其他部分继续将 Cookie 视为其唯一的身份验证凭据,唯一的区别是这些 Cookie 是短期的。这允许在复杂的现有设置上进行部署,通常无需更改与身份验证无关的端点。
2. 如果浏览器即将发出一个已被指示包含此类 Cookie 但尚未拥有该 Cookie 的请求,它将推迟发出该请求,直到刷新完成。虽然这可能会给此类情况增加延迟,但也意味着非身份验证端点不需要容忍未经身份验证的请求或响应任何类型的重试逻辑或重定向。这再次允许在现有端点进行极少的更改即可部署。
请注意,可以通过浏览器以其他方式缓解请求推迟带来的延迟,我们将在后面讨论。
### TPM 考量
DBSC 依赖于用户设备具有一种在保护私钥不被恶意软件泄露的同时签署挑战的方法。这通常意味着浏览器需要访问设备上的可信平台模块 (TPM),但这并不总是可用。TPM 也有延迟高且不可靠的名声。拥有 TPM 是安装 Windows 11 的要求,并且可以在以前的版本上使用。虽然 Chrome 的初始实现需要 TPM,但这并不是协议要求的。浏览器实现者可以自由选择其他密钥存储技术,例如 VBS 密钥。
Chrome 已经进行了研究以了解 TPM 的可用性,从而了解安全会话的可行性。目前的数据显示,大约 60% 的 Windows 用户(并且还在不断增长)将获得保护。还对当前的 TPM 群体进行了研究,包括延迟和可预测性。目前签名操作的延迟为 (P50: 200ms / P95: 600ms)。错误率非常低,目前约为 0.001%。我们的所有研究都是针对使用 ECDSA_P256 算法的公钥加密。
基于这项研究,TPM 广泛可用,并且其延迟和一致性对于建议的用途来说是可以接受的。
### 隐私考量
该协议的一个重要高层目标是不会为用户跟踪引入任何额外的表面:实现此 API(对于浏览器)或启用它(对于网站)不应涉及任何重大的用户隐私权衡。
为了确保我们实现这一目标,有几个显而易见的考量:
- 会话/密钥材料的生命周期:这不应提供任何额外的客户端数据存储(即伪 Cookie)。因此,我们要求浏览器必须在清除其他站点数据(如 Cookie)时清除会话和密钥。
- 跨站点/跨源数据泄露:站点应无法使用此 API 绕过同源策略、第三方 Cookie 策略等。(更多内容见下文。)
- 实现此 API 不应显着增加启发式设备指纹信号的熵。(例如,它不应泄露任何基于 TPM 的稳定设备标识符。)
- 此 API 允许在用户未直接活动时向刷新端点发送后台“ping”,不得在用户已从连接的站点导航离开时启用对用户的长期跟踪。
- 每个会话都会创建一个单独的新密钥,并且应该无法检测出不同的会话是否来自同一台设备。
- 注册和刷新只能通过安全连接(或在测试时使用 localhost)执行。
为了实现这些目标,我们对 DBSC 请求添加了以下约束:
- 注册和刷新是在触发它们的请求的上下文中进行的。对于注册,这是提供 Secure-Session-Registration header 的请求。对于刷新,这是由于缺少 Cookie 而推迟的请求。
- 只有在 Cookie 可访问时才会进行 Cookie 刷新。如果阻止了第三方 Cookie,DBSC 将不会尝试刷新第三方 Cookie。
- 只有在 Storage Access API 已授予访问第一方状态权限的情况下,才会从跨站点上下文进行刷新。这缓解了对与站点最近交互的计时侧信道,并且与未分区的 DBSC 会话是一种第一方状态是一致的。
- 主动刷新必须只有在任何选项卡已加载站点的页面时才会发生。
### 企业支持
虽然 DBSC 解决了会话劫持的一般问题,并且可以适用于任何_浏览器_消费者,但可以扩展此协议以更好地支持企业用例。通过向密钥生成添加具体细节,我们可以为企业用户提供更安全的环境。这是 DBSC(E) 的目标,它是 DBSC 的扩展。DBSC(E) 的高层设计在 [DBSC(E) Overview](./DBSCE/Overview.md) 中描述。
DBSC(E) 消除了 DBSC 具有的漏洞,即如果恶意软件在密钥生成期间已存在于设备上,则可能会接管会话。DBSC(E) 建议通过引入设备密钥链来缓解此漏洞:有关 DBSC 重要性的更多详细信息请参见此处:[Why DBSC(E)?](./DBSCE/Overview.md/#why-dbsce)
## 高层概述

[Link to editable diagram](https://sequencediagram.org/index.html#initialData=A4QwTgLglgxloDsIAIBEAVACgWVckAzshAFCiSzwhJoBCYA9gO4ECmYehyARmeNHEQpUAZXYA3dpyJMScktwC0APiYAuZASgBzBIqgJkAMwA2zEkxXcNAJgAMd5EwD0W3awAm+wzAZJWSAA0yGCsBMB+bMgGMCYArh5hyAAWrCCJYMQMmhD8mqwwcaH5BFp+AHTIyAA6CAASaRkaqKIFRayKYqVQfooASqzaUAQQYCDQfhrl08gwySAmJgHarAC80+UttQAUcwtLCCshrACOcVChHsYMmcBgUOLjrMgA1qwAnsh3DAxGyL9fBilMJlBAAShICAYEGeDEkmWsPEYLHY0QQUGgTyIbG6fh4Bg8Bm0tW4hE8-0MqXSqLuYQCMFYChUEA0oTOYRQMFCT1eH1AFxIECsrNYECKhmAcW4JlgvPekOhsPhPA0XLSMOQACkAOroJzOPaLZaMpTKFlsuIczQ6Qw69CC4XHMVgW26626cbtJmqDSYADyIj1rjaoRxoNcuUgYZ6hlqtRaAG9UAttKg1BtgqgIO9gGnUB5uAQYABqABWTAgqEz5ZeeYAPJLpbAAPpvd7KVAAXyTpegaY2nZayAVGrhqPUORuz0bMpgcuCHJATYIyRKoIsjvsjhcvgYLygz2oV2jeIAkgAREkMDyfGLxRLY3zAWF-Xf7pLbG46AzIYtfcbJGCcYIFSTRoK0QoAMI-O+GggHEEDJM2b4HlsCDcNe7zNKgSYnggzZQIkSBQEYB4cOm0yDqgJCrKsIgMAAts80BMf+wIEBstEjkqqKInEbCZLEsAvEQMoIC81y3AByCuIxBR+DCSDeoicwFBJJH-PcQwIMWoCIccZwXEkGFxAgVwoYyCwoCZZmzDBB7IFCKAWkZHjehOADiACiQYEHJvj+EpljKIiW76gFimkKwJhRDZ5n2c8LmXMpqqpDA6l-El5IWUQrAAB7DKQVkGeclx2XuDm0mwNBHo50LIPlwCue5Gjeb5-kKQEpDBaFDjhZ1SnRVEWXxRVzwMcMWiHJpDV5U1yVOTxCIiuyIzIIkRjsGVTDJFASxOM8KycglHHTC1yD+oGMlsIUoYgjGzihEYoarrUoHsNhYgwJ0IYdF0oKKKeHgaAA2nhyAXgAui0G4hWoAAsdgAMzAQ01JgJ9v0-bieiQfMRqHKwzQIKwTCzPjBwrKgADchGrKgeEER4qAbDDi3-MqKnchqdrhRTxreuapyWmtbiuvaQpw064pam6YueqE52Xb5v14Y9rDPWEr0gY0H3gV97TYwDAzhJERPICDdrQ9R7NjpkE6PDKHg8t8AIAhE7ExrD1hhTuCX4LZ4MXleN5orECRJEWDDPv8r4ncgn5aT+f56YBwHvRj+uioo0FjXBCFIRZaEYTe2G4fdfhM11JFkf2lFs4qHO8RoN3tGuMYNSMS4yiunjBKGcRMbUX7aQsJUcudbXXR1gXdZufUuH5rERV1JABG569AA)
安全会话的一般流程如下:
1. 网站请求浏览器启动新会话,提供一个 HTTP 端点来协商注册参数。
2. 浏览器创建一个设备绑定的密钥对,并调用注册 HTTP 端点来设置会话并注册公钥。
3. 服务器响应一个会话标识符,以及有关如何维护会话的说明。这是一个(可能为空的)Cookie 名称列表,浏览器应确保这些 Cookie 存在,以及它们关联的范围。
4. 稍,会话通过服务器请求关闭会话或用户通过清除站点数据清除密钥而关闭。
只要该会话处于活动状态,浏览器就会根据需要执行以下刷新:
1. 对于适用范围内的任何请求,浏览器会检查是否存在必要的 Cookie。如果它们存在,则照常继续。
2. 如果不存在,浏览器在执行以下操作时推迟此类请求。
3. 浏览器联系会话的 HTTP 端点,提供会话标识符,如果服务器要求,还提供相关私钥的必要持有证明。
4. 如果服务器对证明满意,它会使用常规 Set-Cookie header 建立具有适当 Max-Age 的必要 Cookie。响应还可以包含一组更新的说明,例如,如果服务器希望更改哪些 Cookie 受此逻辑约束。
5. 如果在步骤 2 中推迟了任何请求,浏览器现在会发出包含更新 Cookie 集合的这些请求。
6. 如果浏览器预测用户可能很快需要它们,可以选择主动刷新即将过期的 Cookie。这纯粹是一种延迟优化,并非必需。
### 启动会话

[Link to editable diagram](https://sequencediagram.org/index.html#initialData=MoUwTgbuC0B8CqBncACAggcxAOwC4C4VQBjAVzBGlEUQEsB7baAJRA1sVzAENcHsAUAIxh6pAA4pkuCVJA1+KCgEdS83AKSpMOXHFCRw+AAoB5YABUUAemRkKyBY1u5uYXI7qMB2erhAo9FBgKFohOngANAbBAMQA7gAWILz4rOycPHyMKABSAOoWmsjhWHgAPFTgwfigegDC9PQA1rQghNykuIkA+sRNrSA+fgFBqGHoZbjR1eAJyanUXtgotNiZpMTZ6wI4ACZCvv6BwaElk7rzKQRLihwovvEo3Fu0UAJAA)
#### 会话注册 Header
会话启动过程由服务器附加一个带有 Secure-Session-Registration 和适当参数的 header 启动,如下所示:
```
HTTP/1.1 200 OK
Secure-Session-Registration: (RS256 ES256);challenge="challenge_value";path="StartSession"
```
这是一个结构化 header,带有一个表示允许算法(可能是 ES256 和 RS256)的令牌参数列表。该列表具有多个字符串属性,“path”是必需的,描述要使用的端点,“challenge”是提供注册 JWT 的挑战值。还有一个可选的字符串属性叫做 authorization。一个响应中可以有多个注册:
```
HTTP/1.1 200 OK
Secure-Session-Registration: (ES256 RS256);path="path1";challenge="challenge_value";authorization="authcode"
Secure-Session-Registration: (ES256);path="path2";challenge="challenge_value"
```
一种等效的写法是:
```
HTTP/1.1 200 OK
Secure-Session-Registration: (ES256 RS256);path="path1";challenge="challenge_value";authorization="authcode", (ES256);path="path2";challenge="challenge_value"
```
授权值对于服务器发送是可选的,但对于客户端实现是强制性的。如果存在,它将在 `Authorization` header 中发送到注册端点,并包含在注册 JWT 中。这允许传递不记名令牌,使服务器能够将注册与先前的登录流程联系起来,作为对 Cookie 更传统使用的替代方案。虽然这也可以促进与某些现有基础设施的集成,例如基于 OAuth 2.0 的基础设施,但该参数是通用的,并不限于 OAuth 2.0 中名称相似的 [Authorization Code](https://datatracker.ietf.org/doc/html/rfc6749#section-1.3.1)。
#### 会话注册 JWT
浏览器通过选择兼容的签名算法并为新会话创建一个设备绑定的私钥来响应会话启动。然后它发出以下 HTTP 请求(假设端点 URL 是 https://auth.example.com/securesession):
```
POST /securesession/startsession HTTP/1.1
Host: auth.example.com
Accept: application/json
Cookie: whatever_cookies_already_apply_to_this_request=value;
Secure-Session-Response: JWT Proof
```
JWT 证明使用新创建的私钥签名,并且需要包含以下值(公钥采用 [JWK](https://datatracker.ietf.org/doc/html/rfc7517) 格式):
```
// Header
{
"alg": "Signature Algorithm",
"typ": "dbsc+jwt",
"jwk": "public key JWK",
}
// Payload
{
"jti": "challenge_value",
"authorization": "", // optional, only if set in registration header
}
```
请注意,TPM 的证书链永远不会发送到
服务器。这将允许非常精确的设备指纹识别,与
我们的隐私目标相悖。服务器将只能确认浏览器
仍然可以访问相应的私钥。
#### 会话注册指令 JSON
如果请求得到了适当的授权,服务器将建立代表会话的服务器端状态,并返回以下响应。
```
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Set-Cookie: auth_cookie=abcdef0123; Domain=example.com; Max-Age=600; Secure; HttpOnly; SameSite=None
```
```
{
"session_identifier": "session_id",
"refresh_url": "/RefreshEndpoint",
"scope": {
// Origin-scoped by default (i.e. https://example.com)
"origin": "https://example.com",
// Specifies to include https://*.example.com except excluded subdomains.
// This can only be true if the origin's host is the root eTLD+1.
"include_site": true,
"scope_specification" : [
{ "type": "include", "domain": "trusted.example.com", "path": "/only_trusted_path" },
{ "type": "exclude", "domain": "untrusted.example.com", "path": "/" },
{ "type": "exclude", "domain": "*.example.com", "path": "/static" }
]
},
"credentials": [{
"type": "cookie",
// This specifies the exact cookie that this config applies to. Attributes
// match the cookie attributes in RFC 6265bis and are parsed similarly to
// a normal Set-Cookie line, using the same default values.
"name": "auth_cookie",
"attributes": "Domain=example.com; Path=/; Secure; HttpOnly; SameSite=None"
// Attributes Max-Age and Expires will not contribute to whether a request
// cookie satisfies this credential.
}]
}
```
如果请求没有得到适当的授权,服务器可以通过回答 403 和新的 Secure-Session-Registration header 来请求重新注册。状态码在这里并不特别重要;任何导致注册失败的都可以。
```
HTTP/1.1 403
Secure-Session-Registration: (ES256 RS256);path="/registration";challenge="challenge_value"
```
随后,只要浏览器认为此会话处于“活动”状态,它就会按照上述步骤操作,即在需要时刷新 auth_cookie,如下一节所述。
请注意,如果需要多个 Cookie,服务器将返回多个 Set-Cookie header,并在响应正文的 "credentials" 数组中有相应的条目。
### 维护会话
只要指定的 Cookie 未过期,浏览器将继续照常发送请求。一旦 Cookie 过期,浏览器将暂停 Cookie 范围内的所有请求(服务器在注册中排除的路径除外),同时刷新 Cookie。这就是浏览器驱动的协议发挥作用的地方,如果没有这一点,可能会有许多请求没有所需的 Cookie。
#### 刷新流程

[Link to editable diagram](https://sequencediagram.org/index.html#initialData=A4QwTgLglgxloDsIAICqBnApmZBBA5pkgFCiSzwhLIASmANgCbIBKmAjgK6boTqnhocRCgDK2AG7ZixBAHsImZHKk4M2PISQAacWFUBiAO4ALTCAgAucenRQ5CZDDlyA1lCUhOEEwH1nbh7ImAAewFBgmIzE6jgERBAAtAB8dEysHNy86JbIAOIAogAqwSEgALbA9JgAdM7lAPTAYAqYMIqMvpFcPBDE+C2cwBkAZpHoJshYtvYIMVhxWknJeqqWAAoA8qIlDVgwnOM8dg4NkWM8JsSr2CmxmgmWNEVF68gALAAMAMyyrcqqNALB46G5gYxmCzWNqHTCJGwnBCJADCJhA9GqCEIlhquJq8w08SQKTBG22u32sOmiLOmAuEz+igBGnuRIgukk2Ah5is4gOkXhx1miTY6GADiwOPxYLuwLZTxebwATJ9PoylCoWXKlhz9FzTDzoUlkS53Jhcl4fP5TR4ALwSdHcYhEaLyJmatTahK6wwGqFsaogLDIMzpbpZPjIIxQHxOG08ZDncZmaKspYkzlgXKFEqhCpVWr1JotRTtKJdTK9YhAA)
浏览器通过调用会话端点来刷新短期会话凭据:
```
POST /securesession/refresh HTTP/1.1
Host: auth.example.com
Accept: application/json
Cookie: whatever_cookies_already_apply_to_this_request=value;
Sec-Secure-Session-Id: session_id
```
对此,服务器可以选择先通过向浏览器发出挑战来请求密钥的持有证明,方法是通过带有挑战的 403 响应进行响应。Secure-Session-Challenge header 是一个结构化 header,带有一个挑战值列表,用于指定 "id" 参数:
"challenge_value";id="session_id"。
```
HTTP/1.1 403
Secure-Session-Challenge: "challenge_value";id="session_id"
```
服务器还可以提前将挑战附加到任何响应作为优化,例如:
```
HTTP/1.1 XXX
Secure-Session-Challenge: "challenge_value";id="session_id"
```
也可以向多个会话发送挑战:
```
HTTP/1.1 XXX
Secure-Session-Challenge: "challenge 1";id="session 1"
Secure-Session-Challenge: "challenge 2";id="session 2"
```
这也可以格式化为:
```
HTTP/1.1 XXX
Secure-Session-Challenge: "challenge 1";id="session 1", "challenge 2";id="session 2"
```
因为每个挑战都是一个结构化 header 项。
浏览器使用 Secure-Session-Response header 响应该响应,其中包含一个签名的 JWT:
```
POST /securesession/refresh HTTP/1.1
Secure-Session-Response: JWT proof
```
JWT 证明包含:
```
// Header
{
"alg": "Signature Algorithm",
"typ": "dbsc+jwt",
}
// Payload
{
"jti": "challenge_value",
}
```
如果服务器对响应满意,或者如果它没有请求,则通过设置短期 Cookie 来回答。服务器可以选择在响应正文中调整会话(类似于设置方式)[https://github.com/WICG/dbsc/blob/main/README.md#session-registration-instructions-json]。
```
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Set-Cookie: auth_cookie=abcdef0123; Domain=example.com; Max-Age=600; Secure; HttpOnly; SameSite=None
```
内容是一个与注册期间具有相同规范的 json。
收到此响应后,浏览器释放任何等待此刷新的推迟请求,包括新的 Cookie。
注意:
此响应与会话设置的响应相同,可以由客户端中的相同逻辑处理。
新的一组说明替换会话的任何先前说明。例如,如果这里的 Cookie 名称与之前不同,浏览器不应基于缺少旧的 Cookie 名称来触发刷新。
服务器可能会为短期 Cookie 发出不同的 Max-Age 或范围。
服务器可以在此响应中设置或更新其他不受会话刷新约束的 Cookie,就像在任何响应中一样。
相反,如果服务器决定结束会话,它可以响应:
```
{
"continue": false
}
```
在这种情况下,浏览器应停止为此请求触发任何刷新,释放任何没有短期 Cookie 的推迟请求,并清理和删除关联的会话状态,包括绑定密钥。
#### 结束会话
会话可以通过多种方式结束:
- 服务器可以在刷新期间通过在刷新期间回答 {“continue”: false} 来结束会话
- 服务器可以随时发送带有 Clear-Site-Data: "storage" 或 Clear-Site-Data: "cookies" 的 header
- 用户可以清除站点数据,这将本地清除 Cookie 以及站点的任何注册会话密钥
重要的是,用户始终处于控制地位,并且如果愿意可以删除会话密钥。
## 与其他 API 的交互
### Login Status API
如果 [Login Status API](https://github.com/privacycg/is-logged-in) 发布,我们应该将 DBSC 会话创建限制为已登录。虽然我们对 DBSC 会话的语义立场很弱(它并不一定代表登录状态),但 DBSC 会话是长期存储(如 Cookie)。因此它们应该受到相同的限制。
### 与非活动文档的交互(BFCache, Prerendering)
当出于任何原因结束会话时,任何有权访问该会话凭据的非活动文档都应被销毁。这确保了 BFCache 中的页面或包含受这些凭据保护信息的预渲染页面在会话结束后不会被呈现。这在技术上并不是必需的,因为会话状态本身从来不是主要的身份验证(端点仍然基于 Cookie 进行验证,Cookie 在会话终止时不会被清除)。但会话终止很可能代表用户身份验证的变化,因此我们在这里采取保守立场,即 DBSC 会话终止应该驱逐 BFCache 中的所有文档。
## 未来可能性:StartSession 的 JavaScript API
JavaScript API 目前尚未实现,也不计划作为初始 DBSC 发布的一部分。下面的文本描述了该 API 的一种可能的未来形式。

[Link to editable diagram](https://sequencediagram.org/index.html#initialData=A4QwTgLglgxloDsIAIDqBTARsgCiA5ugFCiSzwhLICqAzumMgIKFInjRyIoDKDAbgyJF8YAPYBXYMh4QOyerVpQxCIhmx5CAWgB8dBs1YQAXMgQh+UfCAhiwAOnowJYdIuWqncyAAoHAQCURAhiEOjIYoKMBows6EgAxADuABbotiYAwm62EQDW6ACeyKBQYESxRgkQenxg0SY4API8ACrIAPTOru7ungjdPhAhYRFRhlXxSAA09dEp6ZkA3gBEmFAIACab+NogADb4JgEOqwC+RPMMelPGJgASbW04yABMAAwfo+GR0TT0OLGOYCBiLDKmPi1LJiMT5KDoMwgCQQVIAfRgsPh6AAvPxDhJiBpcAR0AAebR3GpmYDiAC2UHoDjctDEB0E-iCRASWx+43+xK06BBDTBaQhJj4ShUCGQjPMYmSyBAMGggiIQA)
该 API 可能由一个新的接口 SecureSession 组成,其实例通过 navigator 对象的 securesession 属性获得。SecureSession 接口理想情况下应支持以下方法:
- **startSession():**
- 参数:
- endpoint:安全会话端点的 URL,支持 /startsession 和 /refresh 操作
- supported_binding_algs:服务器支持的加密算法数组
- authorization:可选的授权值,传递给 Start Session HTTP 请求
- 返回:
- 包含会话 ID(可能为空字符串)的字符串的 promise
调用时,此方法必须:
- 生成并存储一个新的、安全的加密密钥对
- 按照下面“启动会话”中的规定调用“endpoint” + /startsession(HTTP 请求/响应)
- 返回一个 promise
- 如果该调用成功(即返回 HTTP 200),则返回从该调用获得的会话 ID(可以是空字符串)
- 如果该调用失败,则抛出异常(可能指示失败调用的 HTTP 状态)
要求:
- 端点必须与 JavaScript 具有相同的源。
以下是理论 API 的使用示例:
```
let promise = navigator.secureSession.start({
// Session start options
"endpoint": "", // required
"supportedBindingAlgorithms": ["ES256,RS256"], // required
"authorization": "", // optional
});
promise.then((sessionInfo) => {
// Success means the browser has completed the session setup with the
// session endpoint and will perform the necessary maintenance tasks
// going forward.
console.log("Session with id {} was started.", sessionInfo.id);
});
promise.catch((...) => {
// Session start failed for some reason, e.g. the HTTP endpoint was
// not reachable, or broke protocol.
});
```
标签:BFCache, Cookie保护, DBC, Device Bound Credentials, Google, JWT, Nuclei, TPM, Web安全, Web标准, WICG, 企业安全, 会话管理, 反钓鱼, 可信平台模块, 浏览器协议, 网络安全, 网络安全, 网络资产管理, 蓝队分析, 账户劫持防护, 隐私保护, 隐私保护