Repository navigation
fix: bind admin sessions to the signing-in device (beta, off by default) - #688
Merged
Merged
Conversation
A signed-in admin session is a cookie, and malware that copies the browser's cookie store can replay it from another machine. The new dbscEnabled setting (Configuration > Security, Beta) binds each admin sign-in to a key the browser keeps in the device's security hardware, using Device Bound Session Credentials. A bound session's requests, the message browser's API calls included, need a second, iron-sealed cookie that lives ten minutes and that only the key can renew, so a copied session cookie stops working within minutes. Logout marks the binding ended rather than deleting it, so a copy of the cookie stays refused after the owner signs out. Browsers without support (anything but Chrome on Windows and macOS today) never register and sign in as before. Chrome only binds on an https origin with a trusted certificate, so the setting reports itself inactive without an https Service URL. lib/dbsc/ holds the protocol (proof verification on Node's own crypto, single use challenges and bindings in Redis), lib/ui-routes/dbsc-routes.js the registration and refresh endpoints. Verified end to end against Chrome 156 on macOS: test/dbsc-test.js covers the protocol on a real hapi server, test/dbsc-jwt-test.js includes proofs Chrome actually sent, and test/e2e/pages-dbsc.spec.js drives a signed Chrome through a public https URL when one is configured.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds opt-in Device Bound Session Credentials (DBSC) for the admin UI, as a quiet beta like MCP: off by default, a Beta badge on the Security page, no README mention.
What it does. With
dbscEnabledon (Configuration > Security, privileged setting), Chrome on Windows and macOS binds each admin sign-in to a key in the device's TPM or Secure Enclave. A bound session's requests, including the message browser'ssess_API calls, need a 10-minute iron-sealedeebcookie that only the key can renew, so a copied session cookie stops working within minutes. Browsers without support never register and work as before. Chrome only binds on an https origin with a trusted certificate, so the row reports itself inactive without an https Service URL.Design notes (also in CLAUDE.md):
ended, so a copy of the cookie stays refused after the owner signs out. The first version deleted the binding at logout;/security-reviewcaught that.SET NX), and challenges are single use and tied to their session and purpose.{"continue": false}for an ended, unknown or switched-off session, a 403 challenge, and a 401 after repeated bad proofs.Verification.
test/dbsc-test.jsdrives the real routes and extensions on a hapi server with generated ES256/RS256 keys.test/dbsc-jwt-test.jsincludes two proofs Chrome actually sent.test/e2e/pages-dbsc.spec.jsruns a signed Chrome against the e2e instance through a public https URL. It passes locally and skips in CI, which lacks a platform key store.pages-adminoverlay flakes and a token-page flake that also fails on clean master.