Skip to content

SYSTEM Cited by 1 source

SAML protocol

SAML (Security Assertion Markup Language; OASIS standard, v2.0 published 2005) is an XML-based protocol for federated single sign-on. An identity provider (IdP) asserts facts about an authenticated user (typically a username or email) to a service provider (SP) via a signed XML document, carried through the end-user's browser over an HTTP POST binding.

Message shape

A minimal SAML response looks like:

<samlp:Response>
  <Assertion ID="_abc">
    <Subject>
      <NameID>admin</NameID>
    </Subject>
    <Conditions NotBefore="..." NotOnOrAfter="..."/>
    ...
  </Assertion>
  <ds:Signature>
    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#_abc">
        <ds:Transforms>...</ds:Transforms>
        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
        <ds:DigestValue>...</ds:DigestValue>
      </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue>...</ds:SignatureValue>
    <ds:KeyInfo>
      <ds:X509Data><ds:X509Certificate>...</ds:X509Certificate></ds:X509Data>
    </ds:KeyInfo>
  </ds:Signature>
</samlp:Response>

The <Assertion> carries the facts; the <ds:Signature> element carries an XML-DSig signature binding the assertion to the IdP's private key. The SP verifies the signature on every incoming response.

Verification chain (the spec's two-stage design)

XML-DSig verification has two logically separate checks that must both pass:

  1. Signature over <ds:SignedInfo>. The SP canonicalises the <ds:SignedInfo> element using the algorithm in <ds:CanonicalizationMethod>, then verifies <ds:SignatureValue> against the canonicalised bytes using the IdP's public key.
  2. Digest over the referenced element. <ds:SignedInfo> contains a <ds:Reference URI="#..."> pointing at the <Assertion> (or the whole response, depending on what was signed); the SP canonicalises the referenced element per <ds:Transforms>, hashes it, and compares to <ds:DigestValue> inside <ds:SignedInfo>.

A correct implementation links these two checks: the signature proves <ds:SignedInfo> came from the IdP; the digest proves the assertion matches what <ds:SignedInfo> references. The weakness the spec invites is the two-stage indirection: what is signed is not the assertion but a different element (<ds:SignedInfo>) that contains a hash of the assertion. Implementations that re-query the document to recover the digest / reference / assertion (rather than operating on the already-verified <ds:SignedInfo> bytes) are vulnerable to XML signature wrapping — most famously via parser differentials when the document is split across two XML parsers (see systems/ruby-saml CVE-2025-25291 + CVE-2025-25292).

Why SAML is hard to implement securely

The 2025 disclosure's closing argument, citing ssoready.com: "it's probably best to disregard the specifications, as following them doesn't help build secure implementations." The spec's own shape — XML documents referenced by URI, canonicalisation transforms on fragments, digests of pre-canonicalisation bytes, signatures over canonicalised pieces — invites extract-then-re-extract implementation patterns that create gaps between the authenticated bytes and the consumed bytes.

Better alternatives for new deployments: OIDC / OAuth2, WebAuthn-based identity federation, or mTLS-based service-identity flows — none of which rely on XML-DSig.

Seen in

Last updated · 319 distilled / 1,201 read