@@ -72,10 +72,10 @@ different situations. Some of the use cases of DBSC are:
72
72
73
73
### Signed in session ### {#example-signin}
74
74
<div class="example" id="signin-example">
75
- A user logs in to his social account. To protect the user's private data the
76
- site protects his logged in session with a DBSC session. If the user tries to
77
- log in with the same cookie file on a different device, the site can detect and
78
- refuse this as an unauthorized user.
75
+ A user logs in to their social account. To protect the user's private data the
76
+ site protects the logged in session with a DBSC session. If malware tries to
77
+ log in with the same cookie file on a different device, the site can detect
78
+ and refuse this as an unauthorized user.
79
79
</div>
80
80
81
81
### Device integrity ### {#example-device-integrity}
@@ -175,7 +175,7 @@ Relying Parties (RPs) could simply establish a DBSC session independently of the
175
175
Identity Provider (IdP). Unfortunately, most IdPs do not require a password if
176
176
the user is already logged in. Without user interaction, malware can use its
177
177
temporary access to the user's machine to mimic the login flow and establish a
178
- DBSC session with a new private key the malware creates and can exfiltrate. This
178
+ DBSC session with a new private key the malware created and can exfiltrate. This
179
179
violates the security goals of DBSC.
180
180
181
181
Therefore, we need to link the RP and IdP session in some way. The simplest way
@@ -185,13 +185,13 @@ device, we trust that the private key is stored securely. But sharing keys acros
185
185
sites has complex privacy properties. In order to mitigate the privacy risks of
186
186
sharing a high-entropy identifier, we require that the RP already know the
187
187
public key and session identifier for the IdP's session. The RP will include the
188
- IdP origin, session id, and key in the ` Secure-Session-Registration` header. If
188
+ IdP origin, session id, and key in the [: Secure-Session-Registration:] header. If
189
189
the key is correct, the user agent will create a session on the RP with the same
190
190
key as the IdP.
191
191
192
192
There is a potential risk that malicious RP and IdPs could unmask users by
193
193
simply guessing many public keys. This would allow a collaborating RP and IdP to
194
- share a user's identity across sites, outside of the intended mechaisms for
194
+ share a user's identity across sites, outside of the intended mechanisms for
195
195
cross-site identity leaking. To prevent this, user agents should include
196
196
significant backoff or quotas on registration attempts (this is also recommended
197
197
to avoid denial of service on the TPM). Note that the security properties of
@@ -200,15 +200,15 @@ the same key pair, so querying whether a user has a specific DBSC public key on
200
200
the IdP is much less than a one bit of entropy.
201
201
202
202
In order to further limit the value of successfully unmasking a user, we also
203
- require opt-in from the IdP through a .well-known. This will ensure that large
203
+ require opt-in from the IdP through a ` .well-known` . This will ensure that large
204
204
groups of sites cannot collaborate to unmask a single high-value user as they
205
205
browse the web.
206
206
207
207
<div class="example" id="federated-sessions-example">
208
208
Suppose the owners of `example.com` also run `example.co.uk`. Login always
209
209
happens on `example.com`, and is propagated to `example.co.uk` through link
210
210
decoration. In order to protect both sites with a DBSC session, `example.com`
211
- should continue to use its existing ` Secure-Session-Registration` header:
211
+ should continue to use its existing [: Secure-Session-Registration:] header:
212
212
213
213
```
214
214
Secure-Session-Registration: (ES256);path="/register";challenge="challenge"
@@ -227,6 +227,7 @@ on `example.com`. This allows DBSC to protect `example.co.uk` without requiring
227
227
users to reauthenticate on `example.com` at login. </div>
228
228
229
229
# Alternatives considered # {#alternatives}
230
+
230
231
## WebAuthn and silent mediation ## {#alternatives-webauthn}
231
232
232
233
# Server considerations # {#server-considerations}
@@ -235,7 +236,7 @@ In order to use DBSC, site owners need to establish two new endpoints:
235
236
the registration endpoint and the refresh endpoint.
236
237
237
238
The registration endpoint is contacted asynchronously after the browser receives
238
- the Secure-Session-Registration header. This endpoint should:
239
+ the [: Secure-Session-Registration:] header. This endpoint should:
239
240
- Serve the session config, including a new session id.
240
241
- Persist and associate the request's public key with the session id.
241
242
@@ -246,21 +247,21 @@ cause browser agents to begin denial-of-service prevention mechanisms, or even
246
247
terminate the session. Both could lead to future requests without bound
247
248
cookies. The expected behavior of this endpoint is:
248
249
- Look up the public key and recent challenges for the session by id.
249
- - Validate the Secure-Session-Response header has signed a recent challenge with
250
+ - Validate the [: Secure-Session-Response:] header has signed a recent challenge with
250
251
the correct key. Note that due to network latency and race conditions, it's
251
252
possible to receive a signature for an old challenge after issuing a new
252
253
challenge.
253
254
- Issue new bound cookies.
254
- - Serve the current session config.
255
+ - Optionally update the current session config.
255
256
256
257
The refresh endpoint is likely to directly leak login state if cross-site
257
- fetches are allowed. Servers can check for a valid Sec-Secure-Session-Id header
258
- to ensure that incoming requests are initiated by the user agent and not a
259
- cross-site request. It's also recommended to set a narrow CORS policy on this
260
- endpoint, not allowing cross-site origins to make requests with credentials. The
261
- CORS integration has been designed to make this possible by implicitly including
262
- credentials when the deferred request does. For similar reasons, it's also
263
- recommended that the refresh endpoint refuse to be embedded via the
258
+ fetches are allowed. Servers can check for a valid [: Sec-Secure-Session-Id:]
259
+ header to ensure that incoming requests are initiated by the user agent and not
260
+ a cross-site request. It's also recommended to set a narrow CORS policy on this
261
+ endpoint and not allow cross-site origins to make requests with credentials. The
262
+ CORS integration for DBSC has been designed to make this possible by implicitly
263
+ including credentials when the deferred request does. For similar reasons, it's
264
+ also recommended that the refresh endpoint refuse to be embedded via the
264
265
`X-Frame-Options` or `Cross-Origin-Resource-Policy` headers.
265
266
266
267
<div class="example" id="timing-leak-cors">
@@ -296,8 +297,9 @@ This document depends on the Infra Standard for a number of foundational
296
297
concepts used in its algorithms and prose [[!INFRA]] .
297
298
298
299
## Session store ## {#framework-session-store}
299
- The user agent maintains a <dfn>session store</dfn> . It is an
300
- [=ordered map=] from [=host/registrable domain=] to [=session by id=] .
300
+ The user agent maintains a <dfn>session store</dfn> . It is an [=ordered map=]
301
+ from [=host/registrable domain=] to [=session by id=] . Sessions should persist
302
+ across user agent restarts.
301
303
302
304
## Sessions by id ## {#framework-sessions-id}
303
305
A <dfn>session by id</dfn> is an [=ordered map=] from
@@ -317,17 +319,17 @@ A <dfn>device bound session</dfn> is a [=struct=] with the following
317
319
: <dfn>cached challenge</dfn>
318
320
:: a [=string=] that is to be used as the next challenge for this session
319
321
: <dfn>session scope</dfn>
320
- :: a [=/session scope=] defining which [=URL=] s are in scope for this session
322
+ :: a [=/session scope=] defining which [=URLs=] are in scope for this session
321
323
: <dfn>session credentials</dfn>
322
- :: a [=list=] of [=session credential=] s used by the session, derived from
323
- [=/ session credentials=]
324
+ :: a [=list=] of [=/ session credentials=] used by the session, derived from
325
+ [=JSON session credentials=]
324
326
: <dfn>expiration timestamp</dfn>
325
327
:: a [=moment=] when this session should be removed.
326
328
: <dfn>session key</dfn>
327
329
:: a key pair used by the session. The private key
328
330
should be stored in a secure manner, see [[#security-considerations]] .
329
331
: <dfn>allowed refresh initiators</dfn>
330
- :: a [=list=] of [=string=] s describing which hosts are allowed to initiate
332
+ :: a [=list=] of [=strings=] describing which hosts are allowed to initiate
331
333
DBSC refreshes due to non-CORS requests. See
332
334
[[#algo-request-allows-refresh]] for details.
333
335
</dl>
@@ -341,7 +343,7 @@ The <dfn>session scope</dfn> is a [=struct=] with the following
341
343
: <dfn>include site</dfn>
342
344
:: a [=boolean=] indicating if the session applies to an entire site or just an origin.
343
345
: <dfn>scope specifications</dfn>
344
- :: a [=list=] of [=scope specification=] s used by the session
346
+ :: a [=list=] of [=/ scope specifications=] used by the session
345
347
</dl>
346
348
347
349
## Scope specification ## {#framework-scope-specification}
@@ -454,10 +456,10 @@ if both `co.uk` and `de` are [=public suffixes=].
454
456
455
457
<div class="example" id="host-pattern-matches-example">
456
458
Some examples of pattern matches:
457
- - `https:// example.com` matches `*`
458
- - `https:// example.com` matches `example.com`
459
- - `https:// example.com` does not match `*.example.com`
460
- - `https:// subdomain.example.com` matches `*.example.com`
459
+ - `example.com` matches `*`
460
+ - `example.com` matches `example.com`
461
+ - `example.com` does not match `*.example.com`
462
+ - `subdomain.example.com` matches `*.example.com`
461
463
</div>
462
464
463
465
</div>
@@ -495,7 +497,7 @@ if both `co.uk` and `de` are [=public suffixes=].
495
497
496
498
## Identify missing session credential ## {#algo-identify-missing-session-credential}
497
499
<div class="algorithm" data-algorithm="identify-missing-session-credential">
498
- Given a [=request=] (|request|) and a [=/list=] of [=/session credential=] s
500
+ Given a [=request=] (|request|) and a [=/list=] of [=/session credentials=]
499
501
(|credentials|), returns a [=boolean=] indicating whether any |credential| in
500
502
|credentials| is missing on |request|.
501
503
@@ -776,8 +778,8 @@ id="add-debug-header">add the debug header</dfn> to a [=request=]
776
778
777
779
# DBSC Formats # {#format}
778
780
## \``Secure-Session-Registration`\` HTTP header field ## {#header-secure-session-registration}
779
- The \` <dfn export http-header id="secure-session-registration-header">
780
- <code>Secure-Session-Registration</code></dfn> \` header field can be used in a
781
+ The <dfn export http-header id="secure-session-registration-header">
782
+ <code>\` Secure-Session-Registration\` </code></dfn> header field can be used in a
781
783
[=response=] by the server to start a new [=/device bound session=] on the
782
784
client.
783
785
@@ -841,8 +843,8 @@ The following <a>sf-parameter</a>s are defined:
841
843
</div>
842
844
843
845
## \``Secure-Session-Challenge`\` HTTP Header Field ## {#header-secure-session-challenge}
844
- The \` <dfn export http-header id="secure-session-challenge-header">
845
- <code>Secure-Session-Challenge</code></dfn> \` header field can be used in a
846
+ The <dfn export http-header id="secure-session-challenge-header">
847
+ <code>\` Secure-Session-Challenge\` </code></dfn> header field can be used in a
846
848
[=response=] by the server to send a challenge to the client that it expects to
847
849
be used in future Secure-Session-Response headers inside the [=DBSC proof=] , or to
848
850
request a newly signed [=DBSC proof=] right away if the [=response/status=]
@@ -855,7 +857,7 @@ The semantics of the item are defined in
855
857
856
858
The processing steps are defined in [[#algo-process-challenge]] .
857
859
858
- ### Secure-Session-Challenge structured header serialization ### {#challenge-structured-header-serialization}
860
+ ### [: Secure-Session-Challenge:] structured header serialization ### {#challenge-structured-header-serialization}
859
861
The [:Secure-Session-Challenge:] is represented as a Structured Field.[[!RFC9651]]
860
862
861
863
In this representation, a challenge is represented by a string.
@@ -895,13 +897,13 @@ case the session ID is optional.
895
897
```
896
898
</div>
897
899
898
- ## ` Secure-Session-Response` HTTP Header Field ## {#header-secure-session-response}
899
- The \` <dfn export http-header id="secure-session-response-header">
900
- <code>Secure-Session-Response</code></dfn> \` header field can be used in the
900
+ ## \`` Secure-Session-Response`\ ` HTTP Header Field ## {#header-secure-session-response}
901
+ The <dfn export http-header id="secure-session-response-header">
902
+ <code>\` Secure-Session-Response\` </code></dfn> header field can be used in the
901
903
[=request=] by the user agent to send a [=DBSC proof=] to the server to prove
902
904
that the client is still in possession of the private key of the session key.
903
905
904
- \` <a http-header><code>Secure-Session-Response</code></a> \` is a structured
906
+ <a http-header><code>\` Secure-Session-Response\` </code></a> is a structured
905
907
header. Its value must be a string. It's ABNF is:
906
908
<pre class="abnf"> SecSessionChallenge = <a>sf-string</a> </pre>
907
909
This string MUST only contain the [=DBSC proof=] JWT. Any <a>sf-parameter</a> s SHOULD be
@@ -914,13 +916,13 @@ ignored.
914
916
```
915
917
</div>
916
918
917
- ## ` Sec-Secure-Session-Id` HTTP Header Field ## {#header-sec-secure-session-id}
918
- The \` <dfn export http-header id="sec-secure-session-id-header">
919
- <code>Sec-Secure-Session-Id</code></dfn> \` header field can be used in the
919
+ ## \`` Sec-Secure-Session-Id`\ ` HTTP Header Field ## {#header-sec-secure-session-id}
920
+ The <dfn export http-header id="sec-secure-session-id-header">
921
+ <code>\` Sec-Secure-Session-Id\` </code></dfn> header field can be used in the
920
922
[=request=] by the user agent to request the current session is refreshed,
921
923
with the current session identifier as a string argument.
922
924
923
- \` <a http-header><code> Sec-Secure-Session-Id</code></a> \` is a structured header.
925
+ [: Sec-Secure-Session-Id:] is a structured header.
924
926
Its value must be a string. It's ABNF is:
925
927
<pre class="abnf"> SecSessionIdentifier = <a>sf-string</a> </pre>
926
928
This string MUST only contain the session identifier. Any parameters SHOULD be
@@ -933,9 +935,9 @@ ignored.
933
935
```
934
936
</div>
935
937
936
- ## ` Secure-Session-Skipped` HTTP header field ## {#header-secure-session-skipped}
937
- The \` <dfn export http-header id="secure-session-skipped-header">
938
- <code>Secure-Session-Skipped</code></dfn> \` header field can be used in a
938
+ ## \`` Secure-Session-Skipped`\ ` HTTP header field ## {#header-secure-session-skipped}
939
+ The <dfn export http-header id="secure-session-skipped-header">
940
+ <code>\` Secure-Session-Skipped\` </code></dfn> header field can be used in a
939
941
[=request=] to indicate that the request is intentionally missing bound
940
942
credentials due to user agent policy.
941
943
@@ -960,18 +962,18 @@ One <a>sf-parameter</a> is defined:
960
962
</div>
961
963
962
964
963
- ## DBSC Session Instruction Format ## {#format-session-instructions}
964
- The server sends <dfn>session instructions</dfn> during session
965
+ ## JSON Session Instruction Format ## {#format-session-instructions}
966
+ The server sends <dfn>JSON session instructions</dfn> during session
965
967
registration and optionally during session refresh. If the response
966
968
contains session instructions, it MUST be in JSON format.
967
969
968
970
At the root of the JSON object, the following keys can exist:
969
971
: session identifier
970
972
:: a [=string=] representing a [=device bound session/session identifier=] .
971
- If this [=session instructions=] is sent during a refresh request this MUST be
973
+ If this [=JSON session instructions=] is sent during a refresh request this MUST be
972
974
the [=device bound session/session identifier=] for the current session. If
973
975
not these instructions SHOULD be ignored.
974
- If this [=session instructions=] is sent during a registration it MUST either
976
+ If this [=JSON session instructions=] is sent during a registration it MUST either
975
977
be a unique identifier for this [=host/registrable domain=] , or it will
976
978
overwrite the current [=device bound session=] with this identifier for the
977
979
current [=host/registrable domain=] .
@@ -989,15 +991,15 @@ At the root of the JSON object, the following keys can exist:
989
991
This key is OPTIONAL, and if not present, the default value will be true.
990
992
991
993
: scope
992
- :: a [=dictionary=] of [= session scope instructions =] describing the request
993
- destinations covered by the session. This field MUST be present.
994
+ :: a [=JSON session scope=] describing the request destinations covered by
995
+ the session. This field MUST be present.
994
996
995
997
: credentials
996
- :: a [=list=] of [=/ session credentials=] describing the cookies protected by
998
+ :: a [=list=] of [=JSON session credentials=] describing the cookies protected by
997
999
this session. This field MUST be present.
998
1000
999
1001
: allowed_refresh_initiators
1000
- :: a [=list=] of [=string=] s describing which hosts are allowed to initiate
1002
+ :: a [=list=] of [=strings=] describing which hosts are allowed to initiate
1001
1003
DBSC refreshes due to non-CORS requests. See
1002
1004
[[#algo-request-allows-refresh]] for details.
1003
1005
@@ -1041,8 +1043,8 @@ At the root of the JSON object, the following keys can exist:
1041
1043
```
1042
1044
</div>
1043
1045
1044
- ## DBSC Session Scope Instruction Format ## {#format-session-scope-instructions}
1045
- The server sends <dfn>session scope instructions </dfn> in the [=session
1046
+ ## JSON Session Scope Instruction Format ## {#format-session-scope-instructions}
1047
+ The server sends a <dfn>JSON session scope</dfn> in the [=JSON session
1046
1048
instructions=] during registration and optionally during session refresh.
1047
1049
1048
1050
At the root of the JSON object, the following keys can exist:
@@ -1056,19 +1058,19 @@ At the root of the JSON object, the following keys can exist:
1056
1058
:: a [=boolean=] indicating if the session is origin-scoped (false) or
1057
1059
site-scoped (true). This key is OPTIONAL; if not present, it will be false
1058
1060
(origin-scoped). Note that this takes precedence over any
1059
- [=session scope rule=] s in [=scope specification=] (see
1061
+ [=JSON session scope rules=] in [=scope specification=] (see
1060
1062
[[#algo-url-in-scope]] ).
1061
1063
1062
1064
: scope_specification
1063
- :: a [=list=] of [=session scope rule=] s describing modifications to the
1065
+ :: a [=list=] of [=JSON session scope rules=] describing modifications to the
1064
1066
default scope (the entire origin or site). This key is OPTIONAL; if not
1065
1067
present, an empty list will be used.
1066
1068
1067
- ## DBSC Session Scope Rule Format ## {#format-session-scope-rule}
1068
- The server sends <dfn>session scope rule </dfn> s in the [=session scope
1069
- instructions=] during registration and optionally during session refresh.
1069
+ ## JSON Session Scope Rule Format ## {#format-session-scope-rule}
1070
+ The server sends <dfn>JSON session scope rules </dfn> in the [=JSON session scope=]
1071
+ during registration and optionally during session refresh.
1070
1072
1071
- At the root of each [=session scope rule=] , the following keys can exist:
1073
+ At the root of each [=JSON session scope rule=] , the following keys can exist:
1072
1074
: type
1073
1075
:: a [=string=] indicating whether the rule includes or excludes destinations.
1074
1076
This key MUST be present, and the value MUST be "include" or "exclude".
@@ -1081,8 +1083,8 @@ At the root of each [=session scope rule=], the following keys can exist:
1081
1083
:: a [=string=] indicating the path-prefixes that should match the rule. This
1082
1084
key MUST be present. See [[#algo-url-in-scope]] for the detailed semantics.
1083
1085
1084
- ## DBSC Session Credentials Format ## {#format-session-credentials}
1085
- The server sends <dfn>session credentials</dfn> in the [=session
1086
+ ## JSON Session Credentials Format ## {#format-session-credentials}
1087
+ The server sends <dfn>JSON session credentials</dfn> in the [=JSON session
1086
1088
instructions=] during registration and optionally during session refresh.
1087
1089
1088
1090
At the root of the JSON object, the following keys can exist:
@@ -1173,11 +1175,11 @@ present:
1173
1175
1174
1176
This specification requires an update to the <a
1175
1177
href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch"> HTTP-network-or-cache
1176
- fetch</a> algorithm. A [=request=] has a <dfn
1177
- for="request"> deferred device bound session ids</dfn> , a [=list=] of [=tuple=] s consisting of:
1178
+ fetch</a> algorithm. A [=request=] has a <dfn for="request">deferred device
1179
+ bound session ids</dfn> , a [=list=] of [=tuples=] consisting of:
1178
1180
- a domain (a [=host/registrable domain=] ).
1179
1181
- a session id (a [=string=] ).
1180
- This list is initially empty. At the end of step 8.21, run
1182
+ This list is initially empty. After computing cookies in step 8.21, run
1181
1183
[[#algo-identify-session-needing-refresh]] . If the resulting
1182
1184
|session| is non-null:
1183
1185
1. Run [[#algo-session-request]] with the returned |session|'s
0 commit comments