Przeniesienie interfejsu administracyjnego na admin.example.com to realna poprawa: trzyma ciasteczka administracyjne z dala od stron publicznych, daje obu aplikacjom osobne pamięci podręczne i pozwala skierować surowszą politykę sieciową na jedną nazwę hosta. To jednak nie jest kontrola CSRF i nie czyni kodu publicznej witryny bezpiecznym do trzymania otwartego przed zalogowanym administratorem. Rozdzielenie zmienia to, co przeglądarka uznaje za granicę, a nie to, co sprawdza serwer, więc wykonaj te cztery kontrole, zanim uznasz sprawę za skończoną.

Czytaj origin i witrynę jako dwa różne słowa

Origin to schemat, host i port, więc https://www.example.com i https://admin.example.com to różne originy. Witryna w rozumieniu SameSite to schemat plus domena rejestrowalna, więc te dwie nazwy hosta to zwykle ta sama witryna. Ta różnica to cała pułapka: atrybut SameSite nie pomoże między siostrzanymi subdomenami, bo przeglądarka wcale nie uznaje żądania za międzywitrynowe. Skieruj interfejs administracyjny na naprawdę inną domenę rejestrowalną, na przykład admin-example.net, a żądanie naprawdę staje się międzywitrynowe, i właśnie tam SameSite=Lax lub Strict zaczyna robić pracę, na której można polegać.

Sprawdź to w przeglądarce, zamiast rozumować o tym.

Załaduj publiczną witrynę, otwórz narzędzia deweloperskie i zobacz, które ciasteczka przeglądarka dołącza do żądania skierowanego na host administracyjny. Jeśli ciasteczko nie ma atrybutu Domain, jest tylko dla hosta i zostaje na swojej nazwie; jeśli niesie Domain=example.com, wędruje do każdej siostry, a nowa subdomena nic ci nie dała dla tego ciasteczka.

Oddziel możliwość odczytania odpowiedzi od wysłania żądania

Polityka tego samego originu ogranicza odczytywanie odpowiedzi między originami. Nie zatrzymuje wysłania żądania i nie powstrzymuje formularza przed przenoszeniem poświadczeń, które przeglądarka już ma. Proste żądanie, z typem zawartości formularza lub zwykłym GET, jest dostarczane bez wstępnej kontroli; potem CORS decyduje, czy wywołujący skrypt może odczytać odpowiedź. CSRF żyje całkowicie po stronie wysyłania.

Dlatego serwer potrzebuje jawnej kontroli dla operacji zmieniających stan. Token synchronizacyjny powiązany z sesją albo ciasteczko podwójnego wysłania porównywane na serwerze pokrywa ten przypadek; porównanie Origin lub Referer warto dodać jako drugą bramę, ale nie jako jedyną, bo nie każde żądanie niesie ten nagłówek i nie każdy pośrednik go zachowuje. Wytyczne OWASP dotyczące zapobiegania CSRF traktują SameSite jako jedną warstwę wśród kilku właśnie z tego powodu.

Zdecyduj, co brama sieciowa naprawdę dowodzi

Lista dozwolonych wyjść VPN przed hostem administracyjnym to dobra kontrola i słabe twierdzenie o tożsamości. Dowodzi, że żądanie przyszło z adresu, który przydziela VPN, który mogą współdzielić wszyscy na tym wyjściu, i nic nie mówi o tym, kto za nim stoi. Traktuj ją jako filtr wejścia, nie jako uwierzytelnienie.

Trzymaj ją niezależnie od kontroli na poziomie żądania. Jeśli lista jest jedyną rzeczą między atakującym a punktem końcowym zmieniającym stan, jedna błędnie skonfigurowana trasa, jeden klient split-tunnel albo jeden pożyczony laptop usuwa kontrolę całkowicie.

Rejestruj także odrzucenia spoza oczekiwanych zakresów. Ich wybuch jest najużyteczniejszym sygnałem, że ktoś bada granicę, którą właśnie zbudowałeś, a cisza jest sygnałem, że filtr w ogóle nie jest osiągany.

Trzymaj ciasteczka, logowanie i autoryzację jawnie

Zakres ciasteczka rozstrzyga większość wyniku. Ciasteczko domeny nadrzędnej jest wysyłane do hosta administracyjnego, więc wstrzyknięcie skryptu na publicznej witrynie może działać z sesją administratora; ciasteczko tylko dla hosta nie może. Preferuj formę tylko dla hosta, dodaj atrybut Secure i używaj prefiksu __Host- tam, gdzie platforma go wspiera, bo ten prefiks wymaga Secure, Path=/ i braku atrybutu Domain. Czytaj nagłówek odpowiedzi, a nie słoik ciasteczek: Set-Cookie: __Host-admin_session=...; Secure; Path=/; HttpOnly; SameSite=Lax, bez atrybutu Domain. Przeglądarka odrzuca ciasteczko __Host- z Domain, więc ciasteczko, które wciąż widać na siostrzanych hostach, jest dowodem, że prefiks nigdy nie został zastosowany.

Potem trzymaj autoryzację na serwerze, dla każdego żądania, na każdym administracyjnym punkcie końcowym, nie tylko przy logowaniu. Żądanie z dozwolonej sieci nadal musi zostać uwierzytelnione i autoryzowane do operacji, o którą prosi; nazwa hosta nie jest aktorem. Jeśli publiczna i administracyjna aplikacja dzielą przepływ logowania albo magazyn sesji, zapisz ten związek, bo to najkrótsza droga od błędu na publicznej witrynie do administracyjnego działania.

Sprawdź granicę ponownie po rozdzieleniu

Uruchom testy negatywne, nie tylko szczęśliwą ścieżkę: formularz międzywitrynowy bez tokenu musi zostać odrzucony, token z innej sesji musi zostać odrzucony, a żaden GET nie może zmieniać stanu. Sprawdź atrybuty ciasteczek w narzędziach deweloperskich, potwierdź, że kontrola Origin uruchamia się przy niepasującym żądaniu, i spróbuj hosta administracyjnego spoza zakresu VPN, żeby zobaczyć filtr w działaniu.

Nic z tego nie usuwa wady XSS wewnątrz samej aplikacji administracyjnej. Odrębna nazwa hosta to granica izolacji po stronie przeglądarki o realnej wartości i nie zastępuje zapobiegania niebezpiecznemu wykonywaniu kodu ani ochrony żądań po stronie serwera. Po rozdzieleniu lista jest krótsza, niż wygląda: odrębny origin, ciasteczka tylko dla hosta, token przy każdej zmianie, filtr wejścia, któremu nie ufasz jako tożsamości, i autoryzacja rozstrzygana dla każdego żądania.

Powiązane artykuły