Przejdź do treści
INDEKS ANALIZ BREACHROAD / NOTA TECHNICZNA
Bezpieczeństwo tożsamości

Pentest SAML 2.0: signature wrapping i błędy SSO

Techniczna metodyka pentestu SAML 2.0: podpis XML, signature wrapping, Audience, Destination, Recipient, replay, RelayState i rotacja kluczy IdP.

MATERIAŁ PUBLICZNY
AUTOR
/ Pentester (OSCP, PNPT)
PUBLIKACJA
29 kwietnia 2026
CZAS CZYTANIA
22 min czytania
TEMAT
Bezpieczeństwo tożsamości
Pentest SAML 2.0: signature wrapping i błędy SSO

Pentest SAML 2.0 musi odpowiedzieć na dwa odrębne pytania: czy komunikat jest kryptograficznie poprawny oraz czy aplikacja podejmuje decyzję na podstawie dokładnie tego elementu, który został zweryfikowany. Wiele poważnych błędów SSO powstaje nie przez złamanie podpisu, lecz przez rozbieżność między biblioteką XML Signature, parserem dokumentu i kodem mapującym assertion na sesję użytkownika.

Ten przewodnik przedstawia bezpieczną, techniczną metodykę testowania Service Providera, integracji z Identity Providerem, metadanych, podpisów, szyfrowania, ochrony przed replay i logiki RelayState. Opiera się na specyfikacjach OASIS, W3C i wskazówkach OWASP. Testy należy wykonywać wyłącznie w uzgodnionym środowisku i na kontach kontrolowanych przez zespół.

Model SAML 2.0 w pięciu elementach

W typowym Web Browser SSO uczestniczą:

  • użytkownik i jego przeglądarka;
  • Service Provider (SP), czyli aplikacja docelowa;
  • Identity Provider (IdP), który uwierzytelnia użytkownika;
  • AuthnRequest wysyłany przez SP;
  • Response zawierający jedną lub więcej assertions oraz statementy.

W przepływie SP-initiated aplikacja tworzy żądanie i przekazuje użytkownika do IdP. Po uwierzytelnieniu IdP dostarcza odpowiedź do Assertion Consumer Service (ACS). SP weryfikuje strukturę, podpis, czas, odbiorcę, audience i powiązanie z wcześniejszym requestem, a dopiero potem tworzy sesję.

W IdP-initiated brakuje wcześniejszego AuthnRequest, więc nie można oprzeć ochrony na InResponseTo. Taki przepływ jest trudniejszy do ochrony przed niezamówionymi odpowiedziami i session confusion. Jeśli biznes go nie potrzebuje, warto go wyłączyć; jeśli potrzebuje — osobno udokumentować kompensujące kontrole.

Co może być podpisane w dokumencie SAML

Podpis XML może chronić Response, Assertion albo oba elementy, zależnie od profilu i konfiguracji. Nie istnieje bezpieczna reguła „znaleźliśmy gdzieś poprawny podpis”. SP musi wiedzieć, który element zgodnie z kontraktem ma być podpisany, zweryfikować go wobec zaufanego klucza IdP i używać właśnie zweryfikowanego obiektu.

Istotne są trzy poziomy:

PoziomPytanie audytoweRyzyko
KryptografiaCzy podpis matematycznie zgadza się dla wskazanego elementu?modyfikacja podpisanej treści
Struktura XMLCzy referencja wskazuje jeden, dozwolony element o unikalnym ID?signature wrapping lub parser differential
Logika aplikacjiCzy sesja powstaje z danych tego samego zweryfikowanego elementu?zaakceptowanie niepodpisanej assertion

W3C XML Signature pozwala podpisywać wskazany fragment dokumentu przez URI reference i transformacje. Elastyczność standardu wymaga restrykcyjnego profilu aplikacyjnego. Im więcej dowolności akceptuje parser, tym większa przestrzeń do rozbieżności.

XML Signature Wrapping: mechanizm klasy błędów

XML Signature Wrapping (XSW) wykorzystuje sytuację, w której podpis nadal wskazuje oryginalny, niezmieniony element, ale aplikacja pobiera dane uwierzytelniające z innego elementu w zmodyfikowanej strukturze. Atakujący nie fałszuje podpisu. Próbuje sprawić, by walidator i kod biznesowy „patrzyły” w różne miejsca.

Bezpieczna implementacja powinna:

  • przeprowadzić ścisłą walidację schematu przy użyciu lokalnych, zaufanych kopii XSD;
  • odrzucić dokument z nieoczekiwaną liczbą Response, Assertion, Subject lub podpisów;
  • wymagać unikalności atrybutów ID i wiązać referencję z jednym elementem;
  • użyć absolutnego wyboru dozwolonego elementu, a nie zapytania typu „pierwsza Assertion w dokumencie”;
  • po walidacji przekazać do logiki wyłącznie zweryfikowany obiekt;
  • odrzucić nieznane lub nieoczekiwane rozszerzenia, jeśli nie należą do profilu.

Test XSW ma potwierdzić zachowanie parsera, a nie dostarczać uniwersalny payload. Struktura zależy od biblioteki, bindingu i konfiguracji. W raporcie wystarczy minimalny, zanonimizowany dowód, że aplikacja utworzyła sesję na podstawie elementu nieobjętego zaufanym podpisem.

Zaufanie do klucza: metadata, nie dowolne KeyInfo

Dokument może zawierać KeyInfo, ale aplikacja nie powinna uznawać dowolnego klucza dostarczonego wewnątrz niezaufanej wiadomości za zaufany. Klucz weryfikacyjny musi pochodzić z zatwierdzonej konfiguracji lub zweryfikowanych metadanych IdP. W przeciwnym razie atakujący mógłby podpisać własną wiadomość własnym kluczem i dołączyć go do dokumentu.

Audyt obejmuje sposób pobierania metadanych, zabezpieczenie URL, pinning encji, walidację podpisu metadanych, cache, rotację i tryb awarii. Automatyczne pobieranie z adresu kontrolowanego przez konfigurację użytkownika może łączyć błąd z SSRF i bezpieczeństwem połączeń wychodzących. Metadane nie powinny być odświeżane bez limitu w ścieżce logowania.

Przy rotacji IdP często publikuje stary i nowy certyfikat przez okres przejściowy. SP powinien akceptować wyłącznie klucze przypisane do właściwej encji i przeznaczenia, a po migracji usunąć stary klucz. Ręczne kopiowanie certyfikatów bez ownera tworzy długotrwałe wyjątki.

Walidacja Response i Assertion

Poprawny podpis jest dopiero początkiem. SP powinien sprawdzić pełen kontekst wiadomości. Kluczowe pola i pytania:

Destination

Czy odpowiedź jest przeznaczona dla dokładnego ACS, który ją odbiera? Porównanie musi używać skonfigurowanego adresu, a nie wartości z niezaufanego nagłówka Host. Proxy i wiele domen wymagają jednoznacznej normalizacji.

AudienceRestriction

Czy assertion została wydana dla tego Service Providera? Bez tej walidacji odpowiedź dla innej aplikacji w tym samym ekosystemie mogłaby zostać zaakceptowana. Entity ID nie musi być adresem URL, ale porównanie powinno być dokładne zgodnie z konfiguracją.

Recipient

Czy bearer SubjectConfirmation kieruje assertion do właściwego odbiorcy? Recipient powinien pasować do ACS i być analizowany razem z warunkami czasowymi.

InResponseTo

Czy odpowiedź i SubjectConfirmation odnoszą się do requestu utworzonego przez bieżącą sesję SP? Identyfikator żądania powinien być nieprzewidywalny, zapisany po stronie serwera, jednorazowy i powiązany z kontekstem użytkownika.

NotBefore i NotOnOrAfter

Czy assertion jest aktualnie ważna? Dopuszczalny clock skew powinien być niewielki i udokumentowany. Zbyt duży margines powiększa okno replay, a zegary systemów muszą być monitorowane.

Issuer

Czy issuer dokładnie odpowiada oczekiwanemu IdP i relacji konfiguracyjnej? Nie wystarczy podobna domena ani wartość obecna w innym, niezweryfikowanym elemencie.

Status i wersja

Czy response ma właściwą wersję SAML, status sukcesu i oczekiwaną strukturę? Implementacja nie może tworzyć sesji z response błędu tylko dlatego, że gdzieś znajduje się assertion.

Replay: podpisana wiadomość nadal może być użyta ponownie

Podpis chroni integralność, nie gwarantuje jednorazowości. Jeśli ważna response zostanie skopiowana, słaby SP może zaakceptować ją ponownie. Dlatego identyfikatory response i assertion powinny trafić do cache replay na cały okres możliwej ważności, a InResponseTo powinno zostać skonsumowane jeden raz.

Cache musi działać dla całego klastra, a nie tylko w pamięci pojedynczego poda. W przeciwnym razie kolejna próba skierowana na inny węzeł ominie blokadę. Testuj także race condition — dwie niemal równoległe próby tej samej response powinny doprowadzić do utworzenia maksymalnie jednej sesji.

Nie wydłużaj ważności assertions w celu ukrycia problemów z zegarem albo dostępnością IdP. Lepiej naprawić synchronizację czasu i odporność przepływu niż zwiększać okno, w którym przechwycona wiadomość działa.

RelayState i ochrona stanu

RelayState przenosi stan aplikacji przez przekierowanie SSO, często adres docelowy po zalogowaniu. Jeśli SP używa go jako dowolnego URL, powstaje open redirect ułatwiający phishing. Jeśli przechowuje w nim decyzję o roli lub tenantcie bez integralności, może dojść do manipulacji kontekstem.

Bezpieczniejsze podejście to losowy, jednorazowy identyfikator wskazujący stan zapisany po stronie serwera. Jeżeli wartość musi nieść dane, zapewnij integralność, krótki czas życia i ścisłą allowlistę miejsc docelowych. Powiąż RelayState z request ID i sesją rozpoczynającą logowanie.

Przetestuj brak wartości, duplikaty parametrów, zmianę kodowania, URL absolutny, schemat //host, alternatywne porty i ścieżki. Celem jest sprawdzenie normalizacji i logiki, nie omijanie filtrów poza uzgodnionym środowiskiem.

Algorytmy, canonicalization i parser XML

Polityka powinna jawnie określać dozwolone algorytmy podpisu, digest i canonicalization zgodnie z możliwościami biblioteki oraz profilem partnera. Nie polegaj na ustawieniach domyślnych, które mogą zmienić się po aktualizacji. Odrzuć niedozwolone lub nieznane algorytmy przed wykonaniem kosztownych operacji.

Parser XML musi wyłączać niepotrzebne funkcje zewnętrznych encji i pobierania zasobów. SAML processing nie powinien wykonywać żądań sieciowych na podstawie DTD, schematu lub transformacji dostarczonych w wiadomości. Używaj lokalnych, przypiętych schematów, aby ograniczyć XXE, SSRF i denial of service.

Limity rozmiaru dokumentu, liczby elementów, głębokości, liczby referencji i czasu przetwarzania chronią endpoint ACS przed algorytmicznym DoS. Jest to szczególnie ważne, ponieważ endpoint musi przetworzyć część wiadomości przed uwierzytelnieniem użytkownika.

Czy assertion musi być szyfrowana

Podpis i szyfrowanie mają różne cele. Podpis zapewnia integralność i autentyczność; szyfrowanie ogranicza ujawnienie atrybutów pośrednikom i przeglądarce. HTTPS pozostaje wymagany nawet przy EncryptedAssertion. Decyzja zależy od wrażliwości atrybutów i architektury, ale aplikacja musi konsekwentnie wymagać uzgodnionego profilu.

Jeżeli SP akceptuje zarówno szyfrowaną, jak i jawną assertion, atakujący może próbować sprowadzić przepływ do słabszego wariantu. Przetestuj, czy konfiguracja naprawdę wymusza szyfrowanie, jak chroniony i rotowany jest klucz deszyfrujący oraz czy błędy nie ujawniają szczegółów kryptograficznych.

Mapowanie atrybutów i przejęcie konta

Po poprawnej walidacji SAML aplikacja mapuje NameID i atrybuty na lokalne konto. To częste miejsce krytycznych błędów. E-mail nie zawsze jest stabilnym, unikalnym i zweryfikowanym identyfikatorem. Zmiana domeny, wielkości liter, aliasów lub IdP może połączyć użytkownika z niewłaściwym rekordem.

Preferuj niezmienny identyfikator użytkownika w ramach konkretnego issuera. Klucz mapowania powinien obejmować co najmniej issuer/IdP i identyfikator podmiotu, a nie sam e-mail. Automatyczne tworzenie konta (JIT provisioning) musi ograniczać domeny, tenant i role. Atrybut grupy przesłany przez IdP nie powinien nadawać administratora, jeśli kontrakt i allowlista tego nie przewidują.

Testuj konto istniejące, nowe, wyłączone, zmieniony adres, dwa IdP z tym samym e-mailem, brak krytycznego atrybutu i dodatkowe wartości w polu wielowartościowym. Powiąż to z ochroną MFA i zarządzaniem dostępem uprzywilejowanym.

Single Logout i lokalna sesja

SAML SSO nie kończy pracy po utworzeniu sesji. Oceń cookie (Secure, HttpOnly, odpowiedni SameSite), regenerację identyfikatora po logowaniu, maksymalny czas sesji, bezczynność i reakcję na wyłączenie konta. Długa lokalna sesja może pozostać aktywna, mimo że assertion była ważna przez kilka minut.

Single Logout jest złożony i nie każda integracja gwarantuje wylogowanie ze wszystkich usług. Dokumentuj faktyczne zachowanie. Dla krytycznych systemów potrzebny jest mechanizm centralnego cofnięcia sesji lub krótki czas ponownej weryfikacji niezależnie od SLO.

Metodyka pentestu SAML 2.0

1. Zbuduj diagram zaufania

Zapisz entity IDs, ACS, bindings, issuerów, certyfikaty, wymagane podpisy, szyfrowanie, przepływy SP- i IdP-initiated, źródło metadanych oraz mapowanie kont. Ustal, które elementy kończą się na reverse proxy.

2. Przechwyć kontrolny przepływ

Użyj wyłącznie konta testowego. Zidentyfikuj request ID, RelayState, Response, Assertion, podpisy, conditions i atrybuty. Nie umieszczaj aktywnej response ani danych osobowych w raporcie.

3. Wykonaj testy pojedynczych warunków

Zmieniaj jeden warunek naraz: audience, destination, recipient, issuer, czas, request ID, status i strukturę. Oczekuj bezpiecznej odmowy oraz użytecznego logu bez ujawniania sekretów.

4. Sprawdź binding podpisu do obiektu

Zweryfikuj wymaganą lokalizację podpisu, unikalność ID, zaufany klucz i to, z którego obiektu aplikacja pobiera identity. Testy strukturalne wykonuj w bezpiecznym środowisku z limitami.

5. Przetestuj replay i concurrency

Powtórz tę samą response sekwencyjnie oraz równolegle przez różne węzły. Potwierdź jednorazowość request ID i współdzielony cache replay.

6. Oceń provisioning i role

Prześlij kontrolowane warianty atrybutów uzgodnione z właścicielem IdP. Sprawdź mapowanie użytkownika, domenę, grupy, role, deprovisioning i rozdzielenie tenantów.

7. Sprawdź monitoring i rotację

Zweryfikuj logi odrzucenia, alert na nietypowy issuer/audience, rotację klucza IdP, zmianę metadanych oraz procedurę awaryjnego wyłączenia federacji.

Priorytetyzacja ustaleń

Krytyczny jest błąd pozwalający utworzyć sesję innego użytkownika lub administratora bez kontroli jego IdP. Wysoki priorytet ma replay prowadzący do przejęcia aktywnej sesji, akceptacja odpowiedzi dla innego SP albo dowolnego zaufanego klucza. Open redirect w RelayState zwykle wymaga innej oceny, chyba że łączy się z wyciekiem tokenu lub przekonującym phishingiem.

Raport powinien oddzielać:

  • manipulację potwierdzoną end-to-end;
  • brak kontroli wykazany testem negatywnym;
  • konfigurację zwiększającą ryzyko bez potwierdzonego takeover;
  • zalecenie hardeningowe lub odporności operacyjnej.

To zapobiega zawyżaniu wyniku i ułatwia zespołowi naprawę w kolejności faktycznego wpływu. Przygotowanie dowodów i retest warto połączyć z metodyką pentestu aplikacji oraz OWASP ASVS 5.

Checklista dla Service Providera

  • Wymagaj podpisu dokładnie na elemencie określonym przez profil.
  • Weryfikuj klucz z zaufanej konfiguracji lub metadanych, nie z dowolnego KeyInfo.
  • Waliduj lokalny schemat i odrzucaj nieoczekiwaną strukturę.
  • Zapewnij unikalność ID oraz używaj zweryfikowanego obiektu.
  • Sprawdzaj issuer, destination, audience, recipient, czas i status.
  • Dla SP-initiated wymagaj jednorazowego InResponseTo powiązanego z sesją.
  • Utrzymuj współdzielony cache replay.
  • Ogranicz RelayState do integralnie chronionego stanu i dozwolonych celów.
  • Mapuj użytkownika stabilnym identyfikatorem związanym z issuerem.
  • Ogranicz JIT provisioning, grupy i role allowlistą.
  • Monitoruj rotację metadanych, certyfikatów i błędy walidacji.
  • Testuj integrację po aktualizacji biblioteki SAML lub parsera XML.

Najczęstsze pytania

Czy podpisana SAML Response zawsze jest bezpieczna?

Nie. Aplikacja musi wymagać podpisu we właściwym miejscu, ufać właściwemu kluczowi i używać dokładnie zweryfikowanej assertion. Nadal obowiązują audience, recipient, czas i replay.

Czy szyfrowanie assertion zastępuje podpis?

Nie. Szyfrowanie chroni poufność, a podpis autentyczność i integralność. Profil może wymagać obu mechanizmów, a HTTPS pozostaje obowiązkowy.

Czy można ufać e-mailowi jako identyfikatorowi?

Sam e-mail zwykle nie wystarcza. Łącz stabilny subject z konkretnym issuerem i jawnie obsłuż zmianę adresu oraz wiele IdP.

Czy IdP-initiated SSO jest podatnością?

Nie automatycznie, ale brakuje w nim wcześniejszego requestu i silnego powiązania z inicjującą sesją. Wymaga osobnego modelu ryzyka, replay protection i kontroli celu.

Pentest SSO wymaga spojrzenia poza podpis

Breachroad testuje SAML jako cały system: parser XML, kryptografię, warunki protokołu, mapowanie użytkowników, sesję i rotację IdP. Połączenie z testami Active Directory i przeglądem aplikacji pozwala wykazać wpływ od błędnej federacji aż do dostępu do chronionych danych — bez niepotrzebnego ryzyka dla produkcji.

Źródła pierwotne i standardy

UDOSTĘPNIJ / KOPIUJ