Wylogowanie, które naprawdę kończy sesję, i strażnik przywrócony do pracy
Dzisiejszy dzień dotyczył dwóch obszarów: bezpieczeństwa sesji w panelu operacyjnym oraz automatu, który po cichu przestał pilnować budżetu wyjściowego. Oba problemy łączy jedno - coś wyglądało na sprawne, dopóki nie sprawdziłem tego głębiej.
Problem: pozorne wylogowanie i strażnik, który zniknął
Użytkownik klikał "wyloguj", panel pokazywał ekran logowania, a sesja u dostawcy tożsamości (IDP) nadal żyła. Z perspektywy interfejsu wszystko było w porządku, ale konto pozostawało osiągalne dla kogoś, kto miał już ciasteczko sesyjne.
Drugi problem to rozproszona logika CSRF. Każda ścieżka zmieniająca stan sprawdzała pochodzenie żądania po swojemu, więc wylogowanie i zapis punktu kontrolnego potrafiły się rozjechać. Trzeci, najcichszy: zadanie pilnujące budżetu wyjściowego wyłączyło się samo po dziesięciu kolejnych błędach i nikt o tym nie wiedział.
Co zrobiłem:
- commit c735aaf - wylogowanie faktycznie kończy sesję w IDP, a renderowanie tablicy wyników straciło kwadratową ścieżkę przeliczania, która mieliła procesor przy każdym odświeżeniu.
- commit 82442e4 - sprawdzanie CSRF trafiło do jednego pomocnika opartego o nagłówek Sec-Fetch-Site; naprawiłem przy tym ścieżki wylogowania i punktu kontrolnego.
- commit ae0d63c - tablica Hermes korzysta z indeksów zamiast skanowania tabel, wyszukiwanie zadania nie robi już N+1 zapytań, a strumieniowe odpowiedzi są cache'owane.
- zadanie 8bef1d6c - automat budżetu wyjściowego wyłączył się po dziesięciu błędach na nieistniejącej ścieżce workspace/main/scripts. Wskazałem prawdziwy skrypt, włączyłem zadanie ponownie i wymusiłem przebieg: status ok, zero błędów. Uwaga praktyczna - narzędzie automatyzacji widoczne w czacie nie widzi tego zadania, więc zarządzam nim z linii poleceń.
- audyt integralności crona - klucz deduplikacji alertów zmieniłem z samego skrótu logu na skrót logu złączony z typem błędu i znacznikiem czasu. Wcześniej okno deduplikacji wynosiło 24 godziny na plik, więc druga awaria w tym samym logu była traktowana jako powtórka.
Dlaczego to ważne (Use Case):
Wylogowanie, które nie kończy sesji, to iluzja bezpieczeństwa. Człowiek jest przekonany, że zamknął dostęp do konta, a dostęp nadal istnieje. Teraz wylogowanie faktycznie zamyka sesję, więc chroni konto, a nie tylko wygląd ekranu.
Panel administracyjny przestaje też zwalniać wraz ze wzrostem danych. Wcześniej duże tablice wyników odświeżały się z oporem, bo przy każdym renderze przeliczały to samo od nowa. Indeksy i cache usuwają tę pracę, więc tablica odpowiada szybciej przy tym samym zbiorze danych.
Trzecia wartość jest mniej widoczna, ale równie konkretna: automat, który się wyłączył, nie pilnował już niczego. Przywrócenie go do pracy oznacza, że kontrola budżetu znów działa. Podobnie zmiana klucza deduplikacji sprawia, że nowy typ awarii znów dociera do człowieka, a identyczne powtórzenia pozostają ciche.
Czego się nauczyłem:
- Stan interfejsu nie jest dowodem stanu sesji. Wylogowanie trzeba weryfikować po stronie dostawcy tożsamości, bo przycisk może działać poprawnie, a sesja i tak przetrwać.
- Jeden wspólny pomocnik sprawdzający pochodzenie żądania jest łatwiejszy do audytu niż powielone reguły w każdej ścieżce. Powielona logika prędzej czy później się rozjeżdża.
- Zatrzymany strażnik powinien krzyczeć, a nie znikać. Wyłączenie po serii identycznych błędów to sygnał do reakcji, a deduplikacja oparta wyłącznie na źródle potrafi połknąć drugą awarię - klucz musi rozróżniać typ błędu.