Jeden URL dla biura i VPN? Dlaczego mit listy dozwolonych zawodzi
Połączenie VPN nie zmienia adresu, który widzi dozwolona witryna. Sprawdź rzeczywiste wyjście, przeskok zaufanego serwera proxy i ścieżkę IPv6, zanim dodasz URL.
Podłącz tunel, otwórz tę samą zakładkę, a dozwolona witryna odpowiada dokładnie tak, jak robiła to z biura. To założenie, na którym po cichu opiera się większość planów zdalnego dostępu, i obowiązuje ono tylko tak długo, jak trzy odrębne rzeczy pozostają jednocześnie prawdziwe. Żadna z nich nie jest funkcją klienta VPN i żaden rekord DNS nie może dostarczyć którejkolwiek. Gdy zakładka zawodzi w domu, przeglądarka podaje jeden ogólny błąd, niezależnie od tego, czy przyczyną jest brakująca trasa, niezatwierdzony adres wyjściowy czy serwer proxy, który zastąpił zgłaszane źródło. Traktowanie tych trzech jako jednego problemu to droga, na której drobna poprawka polityki zamienia się w tydzień poszerzania list dozwolonych.
Projekt, który przetrwa zetknięcie z prawdziwą siecią biurową, jest węższy niż założenie: jawna tabela decyzyjna z trzema wierszami, jeden punkt egzekwowania, którego nie da się ominąć, oraz test odmowy, który coś dowodzi. Demontaż założenia idzie pierwszy, bo wszystko po nim zależy od wiedzy, która warstwa przedstawia źródło błędnie.
Mit: łączenie to nie routing
Tunel zostaje zestawiony, a klient instaluje trasy dla pewnego zestawu prefiksów. To wszystko, co robi łączenie. Czy niezwiązane żądanie HTTPS przejdzie przez tunel i z jakiego publicznego adresu wydaje się pochodzić, gdy dotrze, to decyzje podejmowane później przez inne komponenty: tabela routingu wybiera ścieżkę, a wyjście wybiera źródło.
Dlatego biuro i stół kuchenny różnią się z tym samym laptopem, tym samym profilem przeglądarki i tą samą zakładką. W biurze żądanie wychodzi przez utrzymywany publiczny adres, na który zgodził się operator witryny. Przez pełny tunel może wyjść przez wyjście VPN, które jest innym adresem i, dopóki ktoś go nie doda, niezatwierdzonym. Przez tunel dzielony może w ogóle nie wejść do tunelu. Tylko dwie z tych trzech ścieżek były kiedykolwiek częścią umowy z właścicielem witryny, a trzecia nie jest usterką, którą trzeba załatać dodatkowym wierszem allow.
Trzy stany żądania, dwa zatwierdzone wyjścia
Zapisz macierz, zanim dotkniesz zapory, bo tabela jest projektem, a reguła tylko jednym jego wdrożeniem. Adresy poniżej to zakresy dokumentacyjne; zastąp je własnymi utrzymywanymi wartościami i trzymaj tam, gdzie właściciel witryny może je audytować.
| Request path | Source the site sees | Intended decision |
|---|---|---|
| Office, no tunnel | Office public exit | Admit to the application login |
| Remote, approved full tunnel | Approved VPN egress | Admit to the same login |
| Remote, ordinary connection | Neither approved address | Deny at the network boundary |
Właśnie w środkowym wierszu większość tych planów się łamie. Liczy się adres, który widzi urządzenie egzekwujące, a nie prywatny adres, który laptop trzyma wewnątrz tunelu, ani jego adres LAN. Wartość taka jak 10.8.0.6 nic nie znaczy dla publicznej witryny, a 192.168.1.44 też nie. Adres tunelu to szczegół adresowania tunelu, a nie poświadczenie, które witryna może sprawdzić.
Jeśli twój VPN nie może zapewnić stabilnego, udokumentowanego wyjścia, macierz nie ma ważnego środkowego wiersza i żadna liczba list dozwolonych go nie wymyśli. Uczciwe opcje to wtedy prywatna witryna osiągana przez jawne trasy prywatne albo brama dostępu świadoma tożsamości przed aplikacją. Obie mają inną umowę niż publiczna lista dozwolonych i obie łatwiej wyjaśnić audytorowi niż listę, która rosła, aż przypadkiem zaczęła działać.
Czytaj źródło tam, gdzie zapada decyzja
Umieść ograniczenie na urządzeniu, które kończy żądanie, i potwierdź, że żadna alternatywna ścieżka pochodzenia go nie omija. Moduł dostępu Nginx ocenia dyrektywy allow i deny po kolei, wygrywa pierwsze dopasowanie, a reguły odziedziczone z bloku otaczającego nadal obowiązują wewnątrz location. Wąskie allow obok szerokiego allow w tym samym miejscu zwykle oznacza, że decyduje szerokie. Przeczytaj całą obowiązującą konfigurację dla tego location, zanim zmienisz choćby jedną jej linię.
server {
listen 443 ssl;
server_name intranet.example.com;
set_real_ip_from 10.20.0.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
location /app/ {
allow 203.0.113.24; # office public exit
allow 198.51.100.77; # approved VPN egress
deny all;
proxy_pass http://app_backend;
}
}
Za modułem równoważenia obciążenia lub odwrotnym proxy ta reguła widzi proxy, chyba że powiesz jej inaczej. Odtwarzaj adres wywołującego tylko przez obsługiwany mechanizm zaufanego proxy, z jawną listą adresów proxy. Nagłówek żądania twierdzący, że adres jest zatwierdzony, nie jest dowodem, że wywołujący go posiada, a na publicznym nasłuchu niezweryfikowany przekazany nagłówek zamienia listę dozwolonych w dekorację.
Następnie sprawdź drugą rodzinę adresów. Zestaw reguł obejmujący tylko IPv4 jest niepełną decyzją dla nazwy hosta, która odpowiada także na AAAA, a klient z działającym IPv6 dotrze do tej samej aplikacji ścieżką, której nigdy nie przejrzałeś.
Tunel dzielony: żądanie, które nigdy nie wchodzi
Tunel dzielony niesie tylko prefiksy ze swojej listy. Wewnętrzne podsieci biurowe zwykle trafiają na tę listę; publiczna witryna nie. Przeglądarka rozwiązuje nazwę, porównuje wybrany adres z tabelą routingu i mimo to znajduje przed sobą lokalną bramę domyślną.
Tak więc żądanie przychodzi z domowego połączenia użytkownika, zostaje odrzucone, a raport mówi, że VPN jest zepsuty, podczas gdy tunel robi dokładnie to, do czego został skonfigurowany. Dwie poprawki są uzasadnione: skieruj ten cel przez tunel i pozwól zatwierdzonemu wyjściu go nieść, albo zaakceptuj, że witryna jest osiągana bezpośrednio, i daj zdalnym użytkownikom inną zatwierdzoną ścieżkę, na przykład bramę dostępu. Poszerzanie publicznej listy dozwolonych witryny, aż przypadkiem znajdzie się na niej adres domowy, nie jest żadnym z nich, i usuwa granicę, którą projekt miał egzekwować. Pierwsze dwie utrzymują macierz uczciwą; trzecia po cichu usuwa z niej wiersz.
Udowodnij odmowę, potem odtworzenie
Testuj żądaniem, które ćwiczy rzeczywistą decyzję, z klienta stojącego w każdym wierszu tabeli. Sprawdzenie osiągalności wobec jakiejś niezwiązanej strony pokazującej adres niczego nie dowodzi, bo ten cel może podążać inną trasą niż aplikacja.
curl -sS -o /dev/null -w 'status=%{http_code}
' https://intranet.example.com/app/login
# repeat with the tunnel up, then with it down
tail -f /var/log/nginx/access.log | grep ' /app/'
Porównaj rekord dostępu na granicy z tym, co przewidziała tabela. Potem opuść tunel i wykonaj nowe żądanie, które powinno zostać odrzucone; już wczytana strona albo już otwarte połączenie nie testuje zupełnie niczego. Jeśli odmowa się nie pojawi, punkt egzekwowania nie jest tam, gdzie sądzisz.
Zachowaj uwierzytelnianie aplikacji po dopuszczeniu do sieci, bo wyjście biurowe i wyjście VPN każde reprezentuje wielu ludzi i żadne nie identyfikuje jednostki. Instrukcja dla użytkowników pozostaje krótka: podnieś zatwierdzony tunel, potem spróbuj ponownie. To właśnie utrzymuje jeden URL wygodnym, podczas gdy reguła źródła pozostaje decyzją, a nie zgadywaniem.