SAML verstehen

SAML im Detail

Die Nachrichten, Signaturen und Prüfungen, die eine Anwendung durchführen muss, mit dem, was ID-Kit bei jedem Schritt tut.

1. Rollen und Vokabular

SAML 2.0 (2005) ist ein OASIS-Standard für Identitätsföderation. Der Identitätsprovider (IdP) authentifiziert den Benutzer und stellt Assertions aus; der Service Provider (SP) verarbeitet sie an der Adresse namens ACS (Assertion Consumer Service). Jede Partei hat einen eindeutigen Bezeichner, die Entity ID, oft eine URL, die nicht erreichbar sein muss.

2. Metadaten

Ein XML-Dokument beschreibt jede Partei: ihre Entity ID, ihre Endpunkte, ihre Zertifikate. Sie zu importieren vermeidet die meisten Kopierfehler.

<md:EntityDescriptor entityID="https://idp.example/idp">
  <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
    <md:KeyDescriptor use="signing">...<ds:X509Certificate>MIIC...</ds:X509Certificate>...</md:KeyDescriptor>
    <md:SingleSignOnService Binding="...HTTP-Redirect" Location="https://idp.example/sso"/>
    <md:SingleSignOnService Binding="...HTTP-POST" Location="https://idp.example/sso"/>
  </md:IDPSSODescriptor>
</md:EntityDescriptor>
  • KeyDescriptor use="signing": das Zertifikat, dessen öffentlicher Schlüssel zur Prüfung von Signaturen dient. use="encryption" ist für die Verschlüsselung.
  • SingleSignOnService (IdP): wohin eine Anfrage gesendet wird, mit dem akzeptierten Binding.
  • AssertionConsumerService (SP): wo die Antwort empfangen wird. WantAssertionsSigned zeigt an, dass der SP eine signierte Assertion verlangt.
  • Zertifikatserneuerung: Veröffentlichen Sie während des Übergangs beide Zertifikate (altes und neues). Ein abgelaufenes Zertifikat ohne veröffentlichten Ersatz blockiert auf einen Schlag alle Anmeldungen.

3. Die zwei Anmeldeszenarien

Von der Anwendung gestartet (SP-initiiert), am häufigsten

Der Benutzer öffnet die Anwendung, die einen AuthnRequest sendet. Die Antwort nennt die ID dieser Anfrage in InResponseTo: Die Anwendung kann prüfen, dass sie diese Antwort tatsächlich angefordert hat. Der Parameter RelayState erlaubt dem Benutzer, zur ursprünglich angeforderten Seite zurückzukehren.

Vom Identitätsprovider gestartet (IdP-initiiert)

Der Benutzer klickt im Portal seiner Organisation auf eine Kachel. Es ging keine Anfrage voraus: Die Antwort kommt „unaufgefordert“ und hat kein InResponseTo. Das ist bequem, aber weniger sicher (die Anwendung kann die Antwort keiner Anfrage zuordnen), und manche Anwendungen lehnen es ab.

4. Bindings: wie die Nachrichten reisen

Der Browser trägt die Nachrichten. Ein Binding beschreibt, wie:

BindingPrincipeUsage
HTTP-RedirectDas XML wird komprimiert (Deflate), Base64-kodiert und dann in die URL gesetzt (?SAMLRequest=…). Ist die Anfrage signiert, liegt die Signatur außerhalb des XML, in den Parametern SigAlg und Signature, und deckt die Zeichenkette SAMLRequest=…&RelayState=…&SigAlg=… so ab, wie sie gesendet wurde.Anfragen (Größe durch die URL begrenzt)
HTTP-POSTDas XML wird Base64-kodiert in ein HTML-Formular gesetzt, das der Browser automatisch absendet. Die Signatur steckt im XML.Antworten (fast immer) und Anfragen
HTTP-ArtifactEs wird nur eine Referenz gesendet; der Inhalt wird direkt von Server zu Server abgeholt.Rare

5. Die Anfrage (AuthnRequest)

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
    ID="_a1b2c3"                                   <!-- identifiant unique, repris dans la réponse -->
    IssueInstant="2026-11-01T10:00:00Z"
    Destination="https://idp.example/sso"          <!-- à qui la demande est adressée -->
    AssertionConsumerServiceURL="https://app.example/saml/acs"   <!-- où renvoyer la réponse -->
    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Version="2.0">
  <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://app.example/metadata</saml:Issuer>  <!-- l'Entity ID de l'application -->
  <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/>
</samlp:AuthnRequest>

Nützliche Optionen: ForceAuthn (neu authentifizieren, auch wenn eine Sitzung besteht), IsPassive (nichts anzeigen, fehlschlagen, wenn der Benutzer nicht bereits angemeldet ist), NameIDPolicy (gewünschtes Bezeichnerformat), RequestedAuthnContext (geforderte Authentifizierungsstufe, zum Beispiel Zwei-Faktor).

6. Die Antwort und die Assertion

<samlp:Response Destination="https://app.example/saml/acs" InResponseTo="_a1b2c3" ...>
  <saml:Issuer>https://idp.example/idp</saml:Issuer>
  <samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status>
  <saml:Assertion ID="_z9y8" IssueInstant="..." Version="2.0">
    <saml:Issuer>https://idp.example/idp</saml:Issuer>
    <ds:Signature>...</ds:Signature>                        <!-- le sceau -->
    <saml:Subject>
      <saml:NameID Format="...emailAddress">jane@example.com</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData InResponseTo="_a1b2c3" Recipient="https://app.example/saml/acs" NotOnOrAfter="..."/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="..." NotOnOrAfter="...">
      <saml:AudienceRestriction><saml:Audience>https://app.example/metadata</saml:Audience></saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="..." SessionIndex="_z9y8">...</saml:AuthnStatement>
    <saml:AttributeStatement>
      <saml:Attribute Name="groups"><saml:AttributeValue>admins</saml:AttributeValue></saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>
</samlp:Response>

Zwei Ebenen: die Response (Umschlag: Status, Ziel) und die Assertion (der Inhalt, auf den es ankommt). Der Status sagt, ob die Identifizierung gelungen ist; bei Misserfolg gibt es keine Assertion.

7. Die XML-Signatur

  • Was signiert wird: die Response, die Assertion oder beides. Die Assertion zu signieren ist das vernünftige Minimum: Sie trägt die Identität.
  • „Enveloped“: Die Signatur wird in das Element gesetzt, das sie signiert (direkt nach dem Issuer), und von der Berechnung ausgeschlossen.
  • Kanonisierung (exc-c14n): Vor der Berechnung des Digests wird das XML normalisiert (Attributreihenfolge, Namespaces, Escaping), damit harmlose Unterschiede wie ein Zeilenumbruch oder ein anderes Präfix die Signatur nicht ungültig machen.
  • Zwei Berechnungen: ein Digest des Elements, dann die RSA-Signatur des SignedInfo-Blocks, der diesen Digest enthält.
  • Algorithmen: RSA-SHA256 ist der aktuelle Standard. SHA-1 ist veraltet: Behalten Sie es nur für Altsysteme.
  • Das Zertifikat in der Signatur beweist nichts: Ein Angreifer kann dort sein eigenes einsetzen. Die Anwendung muss es mit dem vertrauenswürdigen Zertifikat aus den Metadaten des IdP vergleichen.

ID-Kit kann die Assertion, die Antwort oder beides signieren, mit SHA-1/256/384/512, und fehlerhafte Fälle simulieren, um zu prüfen, dass Ihre Anwendung sie ablehnt.

8. Prüfungen auf Anwendungsseite

Der Reihe nach prüft eine seriöse Anwendung:

  1. Der Status ist Success.
  2. Die Signatur ist gültig, mit einem vertrauenswürdigen Zertifikat erstellt und deckt tatsächlich das Element ab, das gelesen wird (Schutz gegen „Signature Wrapping“).
  3. Destination : die ACS URL der Anwendung.
  4. InResponseTo: entspricht einer gesendeten, noch nicht verbrauchten Anfrage (sofern IdP-initiiert nicht erlaubt ist).
  5. Issuer : der erwartete IdP.
  6. Audience : die Entity ID der Anwendung.
  7. NotBefore / NotOnOrAfter: jetzt gültig, mit kleiner Uhrentoleranz (einige Minuten).
  8. SubjectConfirmation: Methode bearer, Recipient = ACS-URL, nicht abgelaufen.
  9. Replay-Schutz: Die Assertion-ID wurde noch nicht verwendet.
  10. Erst dann: NameID und Attribute lesen.

Der Test-SP von ID-Kit führt all diese Prüfungen aus und zeigt sie einzeln, mit der anzuwendenden Lösung.

9. NameID und Attribute

  • NameID-Formate: emailAddress (lesbar, aber die Adresse kann sich ändern), persistent (stabiler Bezeichner für das IdP/SP-Paar, als Kontoschlüssel zu bevorzugen), transient (ändert sich bei jeder Anmeldung), unspecified.
  • Attribute: Name/Wert-Paare, manchmal mehrwertig (Gruppen). Der genaue Name zählt (email, groups oder ein langer Name im URI-Stil bei Microsoft). Der IdP entscheidet, welche Attribute gesendet werden, und die Anwendung muss sie zuordnen.

10. Verschlüsselung und Abmeldung

  • EncryptedAssertion: Der IdP kann die Assertion mit dem Verschlüsselungszertifikat des SP verschlüsseln. Nützlich, wenn die Antwort über eine Zwischenstation läuft, die Sie nicht kontrollieren. Bei einer durchgehenden HTTPS-Verbindung genügt die Signatur im Allgemeinen.
  • Single Logout (SLO): LogoutRequest/LogoutResponse zwischen SP und IdP, über den SessionIndex zugeordnet. In der Praxis ist es der am schlechtesten und am uneinheitlichsten umgesetzte Teil des Standards.

11. Sicherheit: die klassischen Fallstricke

  • XML Signature Wrapping: Der Angreifer schiebt eine gefälschte Assertion neben die echte signierte. Abwehr: prüfen, dass die Signatur genau das gelesene Element referenziert und dass IDs eindeutig sind.
  • XXE: Ein XML-Parser, der externen Entitäten folgt, kann Dateien lesen. Abwehr: DOCTYPE und ENTITY verbieten (ID-Kit tut das).
  • Replay: Eine gestohlene Assertion wird wiederverwendet. Abwehr: kurze Lebensdauer, InResponseTo, Gedächtnis der verbrauchten IDs.
  • Fehlende Signatur akzeptiert: Eine Anwendung, die „eine Signatur prüft, wenn eine vorhanden ist“, aber nicht verlangt, dass sie vorhanden ist, lässt sich umgehen.
  • Audience und Recipient ignoriert: Eine für eine andere Anwendung ausgestellte Assertion würde akzeptiert.
  • Ungeprüfter RelayState: Open Redirect. Abwehr: nur interne Adressen akzeptieren.

Um diese Verhaltensweisen in der Praxis zu testen, nutzen Sie die Fehlersimulationen des ID-Kit-IdP: Ihre Anwendung muss jede davon ablehnen.

Möchten Sie es live sehen? ID-Kit übernimmt die Rolle, die Ihnen fehlt, und zeigt Ihnen jeden Schritt.