Jak OpenConnect zamienia ciasteczko logowania w tunel?
OpenConnect wymienia ciasteczko logowania webowego na tunel VPN. Ciasteczko jest nośnikiem sesji, więc chroń przekazanie, nie tylko stronę logowania.
OpenConnect wiąże dwie osobne wymiany jedną krótkotrwałą wartością: logowanie webowe i tunel VPN. Pierwsza wymiana to zwykły HTTPS: dane uwierzytelniające, podróż SAML albo token idą do bramy, a odpowiedź niesie ciasteczko uwierzytelniania. Druga wymiana przedstawia to ciasteczko tej samej bramie jako dowód, że faza webowa już się odbyła, i dopiero wtedy podnosi się tunel.
Podczas logowania niczego o tunelu się nie negocjuje. To właśnie warto zrozumieć, bo większość błędów w skryptach zakłada, że ciasteczko to hasło do zapisania albo klucz chroniący ruch, tymczasem jest to bilet na okaziciela dla konkretnej sesji bramy.
Co klient i brama wymieniają, po kolei
Faza uwierzytelniania wygląda jak zwykła chroniona witryna. OpenConnect wysyła dane logowania użytkownika albo podąża za przekierowaniem bramy do dostawcy tożsamości, a brama odpowiada dokumentem, który osadza ciasteczko uwierzytelniania. W protokole AnyConnect ta wartość wędruje w nagłówku ciasteczka przy kolejnych żądaniach, zwykle pod nazwą taką jak webvpn, a podręcznik traktuje ją jako dane uwierzytelniające, które niosą sesję dalej.
Druga faza to żądanie CONNECT do punktu końcowego VPN bramy z dołączonym ciasteczkiem. Brama je sprawdza, przydziela adres, a klient uruchamia CSTP nad TLS, przy czym DTLS jest opcjonalną szybszą ścieżką danych, gdy sesja już istnieje. Dopiero w tym momencie ustalane są parametry tunelu, trasy, ustawienia DNS i klucze ruchu sesji. Ciasteczko przeprowadziło klienta przez drzwi; niczego nie zaszyfrowało.
Ta kolejność wyjaśnia, dlaczego istnieje openconnect --authenticate. Uruchom je, a wykona fazę webową, wypisze mały blok zmiennych powłoki, takich jak COOKIE, HOST, CONNECT_URL i FINGERPRINT, po czym zakończy się przed zbudowaniem jakiegokolwiek tunelu. Skrypt opakowujący może wtedy uruchomić prawdziwe połączenie z tymi wartościami, i to jest dokładnie ten podział, którego potrzebuje wdrożenie bez ekranu albo w dwóch kontenerach.
Ciasteczko jest nośnikiem sesji, a nie kluczem
Traktuj wartość tak, jak traktowałbyś identyfikator sesji w aplikacji webowej. Kto ma je w czasie jego życia, może zażądać od bramy tunelu, do którego ta sesja ma prawo, więc jego tajność ma znaczenie. Jednak kopiowanie nie ujawnia ruchu, bo poufność tunelu pochodzi z uzgadniania TLS i pochodnych kluczy, a nie z łańcucha ciasteczka.
Nie jest to też uprawnienie trwałe. Brama i dostawca tożsamości decydują, jak długo żyje sesja, a przeglądarka, która nadal pokazuje zalogowaną stronę, nic nie mówi o tym, czy sesja tunelu jest wciąż ważna. Ponowne połączenie po wygaśnięciu oznacza powtórzenie fazy webowej i wytworzenie świeżego ciasteczka, i to jest właśnie sens ponownego uwierzytelnienia, a nie uciążliwość, którą trzeba obejść inżynierią.
Nie traktuj ciasteczka jako uniwersalnego zamiennika innych danych uwierzytelniających. Asercja SAML, hasło przeglądarki i ciasteczko wydane przez inną usługę to różne obiekty o różnych odbiorcach, a wklejenie jednego w pole drugiego zwykle kończy się niepowodzeniem przy bramie albo, co gorsza, powodzeniem wobec niewłaściwej granicy zaufania.
Przekazywanie ciasteczka bez zostawiania kopii
Najbezpieczniejszym mechanicznym przekazaniem w Linuksie jest standardowe wejście. --cookie-on-stdin czyta wartość ze stdin, więc ciasteczko nigdy nie pojawia się na liście argumentów procesu, gdzie każdy lokalny użytkownik może je odczytać poleceniem ps. Potok, który uwierzytelnia w jednym procesie i karmi tunel w innym, trzyma wartość w potoku, a nie w pliku czy zmiennej środowiskowej.
Argumenty i zmienne środowiskowe są słabsze z różnych powodów. Argument jest widoczny w tablicy procesów przez cały czas życia klienta i często trafia do historii powłoki. Zmienna środowiskowa jest dziedziczona przez procesy potomne, a jednostka systemd, która ustawia ją w pliku jednostki, przechowuje sekret w czytelnej konfiguracji. Jeśli plik jest konieczny, ogranicz go do konta usługi i usuń po zakończeniu sesji.
Utrzymuj też granicę uprawnień świadomie. Proces, który rozmawia z dostawcą tożsamości i być może otwiera przeglądarkę, powinien działać jako użytkownik, do którego należy to logowanie. Proces konfigurujący trasy, DNS i urządzenie tunelu może potrzebować więcej uprawnień. Uruchamianie całej przeglądarki jako root, aby jej ciasteczko było dostępne dla tunelu należącego do roota, to zła wymiana, a nowoczesne konfiguracje OpenConnect potrafią przekazać wartość przez tę granicę wprost.
Rejestrowanie zasługuje na tę samą nieufność. Szczegółowe wyjście klienta, skrypty pomocnicze i diagnostyka bramy mogą powtarzać materiał żądania, a nie każdy poziom logu redaguje ciasteczko. Zapisuj najmniejszy potrzebny rekord błędu, trzymaj go poza kanałami współdzielonymi i sprawdź zredagowaną próbkę, zanim dołączysz ją do zgłoszenia.
Weryfikacja i wygaśnięcie w drugiej fazie
Druga faza nadal musi weryfikować serwer. FINGERPRINT, który wypisuje --authenticate, to przypięcie certyfikatu w formie pin-sha256:, a przekazanie go wywołaniu tunelu z --servercert utrzymuje kontrolę zakotwiczoną w bramie, wobec której się uwierzytelniłeś. Wyłączenie sprawdzania certyfikatów, aby uprościć skrypt, usuwa jedyny dowód, że ciasteczko trafia do zamierzonego hosta.
Gdy brama odrzuca ciasteczko, rozwiązaniem jest nowa runda uwierzytelniania, a nie dłuższy cache. Przechowuj ciasteczko tylko przez czas trwania połączenia, usuwaj pliki tymczasowe przy wyjściu i korzystaj z procesu usuwania sesji dostawcy tożsamości lub bramy, gdy sesja zostanie ujawniona albo urządzenie zginie. Zbuforowane ciasteczko nie jest zwolnieniem z MFA.
Zanim to zautomatyzujesz, sprawdź cztery rzeczy: tunel działa na właściwym koncie, ciasteczko przychodzi przez stdin, odcisk certyfikatu jest przypięty, a sesja jest odrzucana po zamknięciu tunelu. Jeśli czegoś brakuje, automatyzacja rozszerzyła zaufanie do ciasteczka, zamiast odtworzyć ręczny przepływ.