惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
IT之家
IT之家
B
Blog RSS Feed
罗磊的独立博客
GbyAI
GbyAI
博客园 - Franky
Y
Y Combinator Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Google DeepMind News
Google DeepMind News
博客园 - 聂微东
N
Netflix TechBlog - Medium
博客园 - 三生石上(FineUI控件)
人人都是产品经理
人人都是产品经理
U
Unit 42
博客园 - 叶小钗
Jina AI
Jina AI
MyScale Blog
MyScale Blog
雷峰网
雷峰网
B
Blog
Hugging Face - Blog
Hugging Face - Blog
Blog — PlanetScale
Blog — PlanetScale
Recent Announcements
Recent Announcements
腾讯CDC
酷 壳 – CoolShell
酷 壳 – CoolShell

Scott Helme

No Hacking Required: The Manchester Airports Group Data Breach The ultimate road trip combo: Starlink Mini + UniFi Travel Router Device Bound Session Credentials lands in Chrome on macOS Everything I Learned Shipping Device Bound Session Credentials Connection Allowlist: a network firewall, built into the browser Connection Allowlist: a network firewall, built into the browser Top 1 Million Analysis – June 2026: The State of Crypto Top 1 Million Analysis – June 2026: The State of Crypto Top 1 Million Analysis – June 2026: Ten Years of Web Security Top 1 Million Analysis – June 2026: Ten Years of Web Security A dead CDN, a wildcard, and an attack waiting to happen: the netdna-ssl.com takeover A dead CDN, a wildcard, and an attack waiting to happen: the netdna-ssl.com takeover Why No Passkeys? Naming the Top Sites That Still Don't Support Them Why No Passkeys? Naming the Top Sites That Still Don't Support Them The Instructure Canvas Breach (2026): How XSS in a Support Ticket Compromised 275 Million Students The Instructure Canvas Breach (2026): How XSS in a Support Ticket Compromised 275 Million Students Open-Sourcing dbsc-php: a Server Library for Device Bound Session Credentials in PHP Open-Sourcing dbsc-php: a Server Library for Device Bound Session Credentials in PHP DBSC Beta at Report URI DBSC Beta at Report URI Device Bound Session Credentials: Making Stolen Cookies Useless Device Bound Session Credentials: Making Stolen Cookies Useless Passkeys, Permissions Policy and Bug Hunting in 1Password's WebAuthn Wrapper Passkeys, Permissions Policy and Bug Hunting in 1Password's WebAuthn Wrapper Open-Sourcing passkeys-php: A Security-Focused WebAuthn Library for PHP Open-Sourcing passkeys-php: A Security-Focused WebAuthn Library for PHP XSS Is Deadly for Passkeys: The Hidden Risk of Attestation None XSS Is Deadly for Passkeys: The Hidden Risk of Attestation None Passkeys 101: An Introduction to Passkeys and How They Work Passkeys 101: An Introduction to Passkeys and How They Work
Introducing dbsc.dev: Does Your Browser Support DBSC?
https://www.facebook.com/scott.helme · 2026-08-21 · via Scott Helme

Every other web platform feature I've ever written about, I've been able to test in some easy way. Open DevTools, type the name of the thing, see if it's there. Device Bound Session Credentials doesn't work like that: there is no way for a page to ask the browser whether it supports DBSC. None! So I built dbsc.dev, which answers the question the only way I could think to answer it.

A Feature You Cannot Feature-Detect

Here's the thing that makes DBSC unusual. Almost everything we bolt onto the web platform comes with a hook you can poke at from JavaScript.

if (window.PublicKeyCredential) { /* passkeys are available */ }
if ('serviceWorker' in navigator) { /* ... */ }

DBSC has nothing. No navigator.deviceBoundSessions, no constructor, no promise that rejects. The entire protocol lives in HTTP headers, and it's driven by the server, not the page. Your server says "I'd like to bind this session to a device key" and the browser either quietly gets on with it, or it quietly ignores you.

That design is deliberate, and it's a good thing. It's what makes DBSC safe to deploy: a browser that doesn't support it ignores the registration header and carries on with normal cookie auth, so you cannot lock anyone out by switching it on. I've made that point before and I stand by it. But it does leave you with an awkward question if you're on the other side of it, wondering whether your own browser is doing any of this.

You can't ask. You can only find out by trying...

Watching For The Answer

So that's what the site does. When you load dbsc.dev, the response carries a registration header, exactly as a real deployment would:

HTTP/2 200
Cache-Control: no-store
Secure-Session-Registration: (ES256); path="/dbsc/register"; challenge="519aaae6ee95..."

If your browser supports DBSC, it generates a key pair, signs that challenge with the private half, and POSTs the result back to /dbsc/register without any involvement from the page at all. On my machine that round trip takes about 700ms. Meanwhile, the page is polling a status endpoint, waiting to see whether the registration lands.

If it lands, you get a green box. If nothing arrives within eight seconds, you get a red one — and I've been careful about what that red box says. It says no registration attempt arrived in eight seconds. It does not say your browser can't do DBSC, because that's not something this test can prove. Maybe an extension stripped the header. Maybe an enterprise policy turned it off. Maybe you're on a platform with no key store to bind to. The site lists all of that rather than claiming certainty it doesn't have.

The Bit I Actually Wanted To Build

A yes/no answer is fine, but it isn't very interesting, and honestly you can usually guess. What I wanted was to see the protocol in action and make it useful for debugging.

So once your browser registers, the page shows you the whole exchange. The registration JWT your browser sent, decoded. The device public key it generated, as a JWK, with its thumbprint and its PEM. The session instructions the server sent back. A plain fetch() proving the bound cookie is riding your ordinary requests, which is the entire security property in one line.

One detail I enjoyed: the device key doesn't travel where you might expect. The payload of that registration JWT is almost empty.

{
  "jti": "mvt-nE8miIcX--li4LlmEo0bcs5m3BhqJoS2aob76Pc"
}

Just the challenge, signed. The key itself is up in the JWT header, as a jwk alongside "typ": "dbsc+jwt". I had it wrong in my own code until I decoded a real one from Chrome.

While I'm being precise about what the site can and can't tell you: it cannot tell you your key is in a TPM. DBSC carries no attestation, so a server sees a public key and a valid signature and that's it. Anyone claiming otherwise from server-side data alone is guessing.

Watching A Refresh Happen Live

The refresh is the part nobody ever sees, because in production it happens to a cookie you were never looking at. It's also the part that makes DBSC work: the bound cookie is short-lived, and renewing it needs a fresh signature from the device key. Both the cookie and the challenge have to change every single time.

I wanted people to be able to watch that, so I set the bound cookie's lifetime to three minutes. Keep the tab open and you can see your device re-sign, with the old and new cookie values shown side by side. I couldn't go shorter than three minutes as I kept hitting TPM signing quota limits, so apologies for the short wait.

Why You Might Actually Use It

If you're curious, it answers the question of whether or not your browser supports DBSC in just a few seconds, and then shows you the protocol if you'd like to know more.

If you're implementing DBSC, it's a reference exchange you can point at. Here's what a real registration JWT looks like. Here's the two-phase refresh — the 403 with the challenge, then the signed retry. Here's what rotation looks like when it's working. I wrote the server side of this twice before I got the wire protocol right, and a working example would have saved me a fortnight.

If you're filing a bug, there's a copy button that gives you the whole diagnostic as text: the verdict, the decoded JWTs, the key, the timeline, and what your browser told us about itself. Rather more useful in an issue than "DBSC doesn't work for me".

On Privacy

Nothing is retained. Each visit mints a throwaway identifier, and the key material and timeline are deleted within the hour. No IP logging, no analytics on your session, nothing shared. The key you see on the page is a public key your own browser generated for that one page load, and it's worthless to me.

I wanted to be clear on this, given the site's entire subject is device-bound cryptography.

Under The Hood

The server side is dbsc-php, the open source library I extracted from Report URI's production DBSC integration. The site is a couple of hundred lines of PHP on top of it. If you want to run DBSC on your own site and you're in the PHP world, that library carries all the wire-protocol corrections that only surface when you integrate against a real browser — including several I learned about the hard way and wrote up separately.

The site is sponsored by Report URI, same as Why No Passkeys?.

Client Support

Chrome remains the only browser that implements DBSC. It's generally available on Windows, and support has since landed on macOS. Firefox and Safari have nothing. That'll date quickly, which is rather the point of building a site that tests instead of a table that claims.

Go and find out: dbsc.dev

Sources


Have you enjoyed this post or found it helpful?
☕️ Consider buying me a coffee to say thanks!
🔔 Subscribe for free notifications when I publish!
🤩 Become a member and support my content!

Tags: DBSC