How does the SAML Holder-of-Key Web SSO profile bind the assertion to the user's browser, and which attacks does it prevent?
The browser authenticates with a (self-signed) client certificate in a mutual TLS handshake both to the IdP and to the SP; the IdP puts that certificate into the assertion, and the SP accepts it only if the certificate in its own TLS handshake matches; this defeats cross-site scripting and man-in-the-middle theft of the assertion.
* The same client certificate must appear in both TLS handshakes and inside the assertion. *
- The browser requests a resource; the SP sends an
<AuthnRequest>. - The browser forwards it to the IdP over a TLS handshake with bilateral (mutual) authentication. The IdP extracts the browser's client certificate (Cert UA-IdP).
- The user authenticates; the IdP generates a HoK assertion that contains this certificate and returns it to the browser.
- The browser sends the assertion to the SP, again over mutual TLS. The SP extracts the client certificate of this connection (Cert UA-SP).
- The SP checks Cert UA-IdP = Cert UA-SP, then verifies the assertion, and only then grants access.
A stolen assertion is worthless: the thief can present it, but cannot complete the TLS handshake with the victim's certificate, because they lack its private key. That is why the profile prevents both cross-site scripting (a script can read the assertion but not the browser's private key) and man-in-the-middle attacks (an interceptor cannot replay it over its own connection). The certificate can be self-signed because the trust comes from the IdP's signed assertion, not from a CA.
Go deeper:
OASIS: SAML V2.0 Holder-of-Key Web Browser SSO Profile — the specification of the profile.
Mutual authentication: mTLS (Wikipedia) — how a client proves possession of its certificate key during TLS.