Design for a stateless proxy to implement DBSC #235
Replies: 2 comments 5 replies
-
|
This is a neat idea! If we assume a very simple site that doesn't sign its cookies, it just generates a random value and uses it as a bearer token, then this works well. I think the next step up in auth complexity for sites is to sign their cookies, and once sites are doing that they have all the pieces for DBSC except the registration and refresh endpoint. Registration and refresh are both doing crypto operations the site might not want to think through the details of, so providing those implementations could be useful. I'd be surprised if that was best accomplished by a proxy rather than something like a node module. I do think that for those middle-complexity sites that if they need a proxy we've failed in our goal of easy adoption. But there's nothing functionally wrong here, so if there are simple sites that want a proxy then this accomplishes that well! A handful of thoughts:
|
Beta Was this translation helpful? Give feedback.
-
|
I think I have this working! Here's what I have: https://github.com/benweissmann/dbsc-proxy -- I've only tested it against a stock Django app, but I think it should work for an arbitrary upstream cookie value. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hello! I was thinking about writing an open-source server-side implementation of DBSC as a way to understand the spec better. One idea I had was to write a stateless proxy that could sit in front of an existing web app that uses a session cookie for authentication. The proxy would transparently handle DBSC and replace the long-lived session cookie with a short-lived cookie, handle the DBSC session initialization and refreshes, and then transform that short-lived cookie back to the application's long-lived cookie on each request. The idea would be that instead of having to make any updates to an existing app, you could place this proxy in front of the app to get the benefits of DBSC without any changes to the app itself.
One complexity is state management: the need for a persistent store to map session IDs to public keys and upstream cookie values. I've sketched out a design that would store this data in encrypted cookies, so the proxy itself could be stateless and all persistence would be handled by the client itself. I would love some feedback on this design -- in particular:
challengehave? Here, i've defined the challenge value to be a timestamp and the session ID, signed by the server (so a compromised client can't pre-generate a bunch of signed challenges and then pass those to an attacker to use in the future -- it can't generate future-dated challenges, because the challenges have to be signed by the server).Here's my rough sketch:
Crypto primitives
aead(X)represent the result ofJSON.stringify(X), followed by encryption with Nacl's SecretBox (XSalsa20-Poly1305) using a secret key.hmac(Y)represent a MAC of the string Y using Nacl's Auth (HMAC-SHA-512 truncated to 256 bits)The proxy would be configured with a secret key (used for
aeadandhmac), and it would know which cookie the upstream application is using as a session cookie. For the sake of example, we'll assume that cookie is calledsession, and we'll refer to its value (as set by the upstream application) asupstream_session. The proxy would also be configured with a scope, to be provided in the Session Registration instructions JSON.When the proxy returns a response that contains the header
Set-Cookie: session=upstream_sessionaead({ upstream_session, timestamp })and path/dbsc_proxy/StartSession. Maybe support only theES256algorithm since the public keys are shorter./dbsc_proxy/StartSessionendpointjtivalue to get back{ upstream_session, timestamp }({ upstream_session, pubkey })wherepubkeyis the client-providedjwk/dbsc_proxy/RefreshSession, the configured scope, and credentials of[{ type: cookie, name: session, attributes: Domain=example.com; Path=/; Secure; HttpOnly; SameSite=Lax}]Set-Cookie: session=dbsc_proxy::timestamp;session_id,hmac(timestamp;session_id)header, with the session ID and current timestamp in the cookie value. Set the expiration of this cookie to 15 minutes.On all requests, if there is a
sessioncookie starting withdbsc_proxy:::timestamp;session_id;hmac(timestamp;session_id)({ upstream_session, pubkey })and replace the cookie withupstream_sessionwhen sending the request to the upstream serverSecure-Session-Challengeresponse header, with the valuenew_timestamp;session_id;hmac(new_timestamp;session_id)(same as the session cookie, but with an updated timestamp). We could also do this only if the short-lived cookie is nearing expiration./dbsc_proxy/RefreshSessionendpoint:Secure-Session-Responseis not provided, provide the challengenew_timestamp;session_id;hmac(new_timestamp;session_id)new_timestamp;session_id;hmac(new_timestamp;session_id)new_timestampis recent (1 minute?)Sec-Secure-Session-Id({ upstream_session, pubkey })pubkey.Set-Cookie: session=dbsc_proxy::new_timestamp;session_id,hmac(new_timestamp;session_id)Beta Was this translation helpful? Give feedback.
All reactions