SAML Security Concerns: A → B → back to A


SAML Security Concerns

Threat Model

User starts at Web App A → triggers SAML SSO to Web App B (SP) via IdP → user opens an account at B → redirected back to A.

SAML Assertions & Protocol

Signatures everywhere

  • Require XMLDSig on the Assertion (and ideally the entire Response) using strong algorithms (RSA-SHA256+).
  • Reject alg:none, outdated digests, or unsigned responses.

Audience & recipient checks

  • Validate AudienceRestriction → must match B’s entityID.
  • Validate Recipient on the SubjectConfirmationData → must equal B’s ACS URL.

Replay protection

  • Enforce NotBefore / NotOnOrAfter with small clock skew.
  • Cache Assertion IDs and reject replays (e.g., 5–15 minute window).

InResponseTo binding

  • SP-initiated: check InResponseTo matches your outstanding AuthnRequest ID.
  • IdP-initiated: treat as lower assurance (no InResponseTo)—consider requiring step-up before sensitive actions.

NameID & attributes

  • Prefer persistent NameID (or a stable pair like issuer + NameID). Don’t link accounts on email alone.
  • Encrypt sensitive attributes and/or the whole assertion (SAML encryption).

RequestedAuthnContext & step-up

  • Set RequestedAuthnContext (e.g., MFA) and verify AuthnContextClassRef in the assertion.
  • For “account opening,” perform step-up MFA at B if prior assurance is insufficient.

Bindings & Endpoints

Bindings choice

  • Use HTTP-Redirect (deflate-signed) for AuthnRequest from B → IdP.
  • Use HTTP-POST for IdP → B Response (keeps long, signed assertions intact).
  • Consider Artifact binding if you want to keep assertions out of the browser.

ACS URLs & strict allowlisting

  • Register exact ACS URLs in IdP metadata; no wildcards.
  • B must reject assertions delivered to unexpected ACS endpoints.

RelayState & Post-Login Navigation

RelayState integrity

  • Treat RelayState as untrusted input; bind it to the SP session or HMAC it.
  • Don’t let RelayState become an open redirect—allowlist destinations.

Return to A

  • If B sends a “success” signal back to A, use a signed, short-lived token (JWT or opaque mapped server-side) rather than query flags.
  • A must verify signature/audience/expiry before trusting “account opened”.

XML-Level Pitfalls

XML wrapping & reference attacks

  • Use a well-vetted SAML library; validate that the signed element is the one you actually process.

XXE

  • Disable external entity resolution in your XML parser.

Keys, Metadata, & Rollover

Metadata hygiene

  • Pull IdP/SP metadata over HTTPS; pin entityID and expected certificate fingerprints.

Key rotation

  • Honor kid/cert rollover; maintain overlapping trusted keys during rotation windows.

Sessions, Cookies, & CSRF at B

  • Session fixation: regenerate session on SSO; set cookies Secure, HttpOnly, SameSite (None; Secure only when truly cross-site).
  • CSRF on account-creation: require CSRF token (or SameSite protection), check Origin/Referer, and use idempotency keys to prevent duplicate account creation.
  • Clickjacking: Content-Security-Policy: frame-ancestors 'none'.

Authorization to B’s API

  • If the browser calls B: safeguard with CSRF + user session at B.
  • If A calls B (server-side): do not repurpose the user’s SAML assertion. Use a separate channel (e.g., OAuth2 client credentials) and bind requests to the user’s identity via a signed result from B. Avoid the confused-deputy problem.

Logging & Privacy

  • No secrets/PII in logs: don’t log full SAML responses or URLs.
  • Attribute minimization: request only what B needs for account opening; avoid passing sensitive PII through A if possible.

Quick, Copy-Paste Checklist

  • IdP → B SAML Response & Assertion signed; audience/recipient validated
  • NotBefore/NotOnOrAfter checked; replay cache enabled
  • InResponseTo validated (SP-initiated); IdP-initiated guarded with step-up
  • Persistent identifier used for account linking; encrypted attributes for PII
  • AuthnContext (MFA) requested and verified before account creation
  • HTTP-POST for Response; exact ACS allowlist; safe RelayState
  • XML parser hardened (no XXE); signature wrapping protections in place
  • Session regeneration; cookies Secure/HttpOnly/SameSite; CSRF on creation endpoint
  • IdP/SP metadata over HTTPS; cert pinning & key rollover handled
  • Clear, signed success signal from B → A; no open redirects
  • Minimal attributes; redacted logs