RFC 9700, opublikowany w styczniu 2025 roku jako BCP 240, wskazuje, które elementy utwardzania OAuth 2.0 są MUST, a które tylko SHOULD. Wildcard w redirect URI, pozostawiony w konsoli dostawcy tożsamości, to właśnie ten rodzaj ustawienia, który RFC wyklucza, a czysty kod klienta tego nie zrekompensuje. RFC aktualizuje RFC 6749, RFC 6750 i RFC 6819 oraz ostrzega, że jego stosowanie może zaburzyć interoperacyjność ze starszymi ekosystemami. Mimo to zaleca aktualizację tak szybko, jak to możliwe.
Wymagania według siły
| Ustawienie | Poziom | Stanowisko RFC 9700 |
|---|---|---|
| Porównywanie redirect URI | MUST | Serwery autoryzacji stosują dokładne porównanie ciągów znaków |
| Open redirectory | MUST NOT | Klienci i serwery autoryzacji nie mogą ich udostępniać |
| Ochrona przed CSRF | MUST | Klienci chronią endpoint przekierowania: PKCE, nonce lub jednorazowy state |
| Ochrona przed mix-up, wiele serwerów autoryzacji | REQUIRED | Parametr iss lub równoważna wartość iss; odrębne redirection URI jako rozwiązanie zapasowe |
| PKCE, klienci publiczni | MUST | Wymagane w authorization code grant |
| PKCE, klienci poufni | RECOMMENDED | Klienci OpenID Connect MAY użyć zamiast tego nonce, z dodatkowymi środkami ostrożności |
Wymuszanie code_verifier | MUST | Wymuszane na token endpoint, gdy tylko wysłano poprawny code_challenge |
| Metoda PKCE challenge | SHOULD | Taka, która nie ujawnia verifiera; obecnie wyłącznie S256 |
Implicit grant (response_type=token) | SHOULD NOT | Użyj code lub innego typu, który wydaje tokeny na token endpoint |
| Access tokeny związane z nadawcą (sender-constrained) | SHOULD | Mutual TLS lub DPoP |
| Refresh tokeny, klienci publiczni | MUST | Związane z nadawcą lub rotowane |
Redirect URI: dokładne dopasowanie i brak open redirectorów
Gdy serwer autoryzacji porównuje redirect_uri z żądania z zarejestrowanymi wartościami, musi stosować dokładne porównanie ciągów znaków. Jedynym wyjątkiem jest numer portu w localhostowych redirection URI aplikacji natywnych. Wildcardy, dopasowania po prefiksie i rejestracje typu "dowolna ścieżka pod tym hostem" łamią tę regułę.
Liczy się też sama lista zarejestrowanych adresów, ponieważ każdy wpis to dozwolony cel dla kodów autoryzacyjnych. Usuń nieaktualne wpisy, zwłaszcza hosty, nad którymi już nie panujesz, na przykład wycofaną domenę stagingową, którą ktoś inny mógłby przejąć.
Drugą połową problemu są open redirectory. Endpoint, który przekierowuje przeglądarkę na dowolny URI z parametru zapytania, może doprowadzić do wycieku kodów autoryzacyjnych i access tokenów, a RFC stanowi, że ani klienci, ani serwery autoryzacji nie mogą go udostępniać. Przykład z OWASP, http://example.com/example.php?url=http://malicious.example.com, dobrze pokazuje problem: użytkownik widzi zaufany host i nie zauważa przekierowania.
Ściągawka OWASP o niezwalidowanych przekierowaniach podaje rozwiązanie. Najlepiej mapować po stronie serwera krótki identyfikator na cel, zamiast przyjmować URL. Jeśli musisz przyjąć adres, sparsuj go utrzymywanym parserem i porównaj schemat, kanoniczny host oraz efektywny port z jawną allowlistą. Odrzucaj userinfo i nigdy nie dopasowuj po surowych prefiksach ani sufiksach.
PKCE u każdego klienta, obowiązkowo u publicznych
Klienci publiczni muszą używać PKCE. Dla klientów poufnych jest ono zalecane, bo zatrzymuje także code injection, a przy okazji CSRF. Poufni klienci OpenID Connect mogą zamiast tego użyć nonce i odpowiadającego mu claimu w ID Token, ale tylko z zastrzeżeniami z sekcji 4.5.3.2. Zalecenie dotyczy również aplikacji webowych, choć PKCE projektowano z myślą o aplikacjach natywnych.
- Wartość challenge musi zmieniać się w każdej transakcji. Stała wartość niweczy sens mechanizmu.
- Używaj
S256. RFC 9700 nazywa ją obecnie jedyną metodą, która nie ujawnia verifiera w żądaniu autoryzacyjnym; atakujący, który potrafi odczytać to żądanie, może w przeciwnym razie złamać PKCE. RFC 7636 dodaje, żeplainchroni tylko przed atakującym widzącym wyłącznie odpowiedzi. - Verifier to losowy ciąg od 43 do 128 znaków ze zbioru znaków niezarezerwowanych. RFC 7636 zaleca 32 losowe oktety zakodowane w base64url, co daje 43 znaki.
Serwer musi też blokować downgrade: żądanie tokenu z code_verifier jest akceptowane tylko wtedy, gdy żądanie autoryzacyjne zawierało code_challenge. Publikowanie code_challenge_methods_supported w metadanych serwera pozwala klientom wykryć obsługę PKCE.
Implicit grant, CSRF i mix-up
Klienci nie powinni używać response_type=token ani żadnego typu odpowiedzi, który zwraca access tokeny w odpowiedzi autoryzacyjnej. RFC 9700 uznaje je za podatne na wyciek i replay tokenów oraz zauważa, że nie istnieje standardowa metoda związania z nadawcą tokenu wydanego w ten sposób. Używaj code albo typu, który wydaje tokeny na token endpoint, takiego jak code id_token.
Ochrona przed CSRF na endpoincie przekierowania wymaga PKCE (jeśli klient potwierdził, że serwer je obsługuje), nonce w przepływach OpenID Connect albo jednorazowej wartości state powiązanej z user agentem. Jeśli Twój klient komunikuje się z więcej niż jednym serwerem autoryzacji, użyj parametru iss z RFC 9207 lub równoważnej wartości iss, na przykład claimu z ID Token.
Tokeny: wiąż z nadawcą, gdzie się da
Serwery autoryzacji i serwery zasobów powinny wiązać access tokeny z nadawcą za pomocą mutual TLS (RFC 8705) lub DPoP (RFC 9449), aby skradziony token był bezużyteczny bez odpowiadającego mu sekretu. Refresh tokeny klientów publicznych muszą być związane z nadawcą lub rotowane, zgodnie z opisem w sekcji 4.14 RFC.
Od czego zacząć
- Wypisz wszystkie zarejestrowane redirect URI dla każdego klienta. Usuń wildcardy, częściowe ścieżki i hosty, nad którymi już nie panujesz. Następnie dopisz ścieżkę lub zmień subdomenę w działającym żądaniu autoryzacyjnym; serwer powinien je odrzucić.
- Wyszukaj parametry przekierowania, takie jak
url,nextczyreturnUrl, po stronie klienta i serwera autoryzacji. Zastąp dowolne adresy URL mapowaniem identyfikatorów po stronie serwera lub allowlistą opartą na sparsowanym URL. - Przeszukaj kod klientów i ustawienia serwera pod kątem
response_type=token. Przenieś tych klientów na przepływ authorization code z PKCE iS256. - Przetestuj PKCE bezpośrednio. Wyślij żądanie autoryzacyjne bez
code_challenge, a potem zrealizuj kod zcode_verifier. Następnie zrealizuj kod chroniony PKCE bez verifiera. Oba przypadki powinny zakończyć się błędem na token endpoint; token w odpowiedzi oznacza, że serwer nie przechodzi testu. - Przetestuj
state: odtwórz użytą wartość, a potem wyślij wartość z innej sesji przeglądarki; klient musi odrzucić obie. Jeśli Twój dostawca zwracaiss, zmodyfikuj go i sprawdź, czy klient odrzuca odpowiedź. Claimy ID Token sprawdzisz naszym narzędziem JWT, a jeśli chcesz niezależnej oceny, test penetracyjny może objąć te przepływy. - Dla klientów publicznych wybierz wiązanie z nadawcą albo rotację. Jeśli rotujesz, w teście przedstaw użyty refresh token dwukrotnie i zobacz, jak zareaguje serwer. Znajdź tę próbę w logach serwera autoryzacji, bo nazwy zdarzeń różnią się między produktami, i ustaw na nią alert.
