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.
- AUTOR
- Karol Rapacz / Pentester (OSCP, PNPT)
- PUBLIKACJA
- 29 kwietnia 2026
- CZAS CZYTANIA
- 22 min czytania
- TEMAT
- Bezpieczeństwo tożsamości
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;
AuthnRequestwysyłany przez SP;Responsezawierają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:
| Poziom | Pytanie audytowe | Ryzyko |
|---|---|---|
| Kryptografia | Czy podpis matematycznie zgadza się dla wskazanego elementu? | modyfikacja podpisanej treści |
| Struktura XML | Czy referencja wskazuje jeden, dozwolony element o unikalnym ID? | signature wrapping lub parser differential |
| Logika aplikacji | Czy 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,Subjectlub 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
InResponseTopowią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.