Root nie jest tym, co pozwala aplikacji VPN na Androidzie przenosić ruch, blokować wycieki czy przetrwać restart. Ludzie streszczają to wszystko jako „aplikacja ma uprawnienie VPN”, co ukrywa trzy odrębne mechanizmy: zgodę użytkownika, interfejs pakietów tworzony przez system oraz politykę blokowania platformy, której nie definiuje aplikacja. Ocenianie projektu VPN na Androida oznacza pytanie, na którym z tych trzech naprawdę opiera się dane twierdzenie, bo każde ma innego właściciela i inny tryb awarii.

Zgoda przychodzi przez aktywność systemową

VpnService.prepare() niczego nie przyznaje. Zwraca intent do systemowej aktywności zgody, gdy zgody brakuje, a aplikacja uruchamia ten dialog, aby użytkownik zatwierdził usługę. Uruchomienie własnego procesu aplikacji, dodanie uprawnienia do manifestu czy pokazanie własnego ekranu „włącz VPN” nie tworzy zgody.

Zgoda ma też zakres. Należy do pakietu w profilu użytkownika, więc kopia prywatna i kopia służbowa to osobne decyzje, a właściciel urządzenia może przygotować profil zarządzany inaczej niż prywatny. Jeśli dialog nigdy się nie pojawia i prepare() zwraca null, zgoda już istnieje dla tego pakietu w tym profilu; to nie dowód zaufania do aplikacji, tylko informacja, że uprawnienie jest.

Interfejs jest żądaniem, które spełnia system

Po zgodzie aplikacja opisuje, czego chce, za pomocą VpnService.Builder: adresów, tras, serwerów DNS, MTU oraz, tam gdzie to obsługiwane, aplikacji do włączenia lub wyłączenia. establish() prosi system o utworzenie interfejsu tunelu i skierowanie do niego pasującego ruchu. Decyzja o routingu należy do systemu; aplikacja otrzymuje deskryptor pliku i musi potem zrobić z pakietami coś pożytecznego.

What you observeWho actually owns it
VPN consent dialogThe system, triggered by prepare()
Routes, DNS and app listsThe app requests them; the system applies them
One active VPN per profileThe platform; a new service replaces the old one
Always-on and block-without-VPNDevice policy enforced by the platform

Ta tabela to architektura w jednym miejscu. Aplikacja uczestniczy w obsłudze pakietów; nie posiada interfejsu, tablicy routingu ani liczby usług, które mogą działać.

Gniazdo tunelu musi uciec z własnego tunelu

Połączenie przenoszące zaszyfrowany ruch samo jest gniazdem. Jeśli zostanie skierowane z powrotem do interfejsu, który aplikacja właśnie utworzyła, tunel zależy od tunelu i zastyga. VpnService.protect() wiąże to gniazdo z siecią podkładową, aby omijało przechwytywanie, i dlatego poprawny klient chroni swoje zewnętrzne gniazdo przed pierwszym uściskiem dłoni.

adb shell dumpsys connectivity | grep -i -A5 vpn
adb shell settings get global always_on_vpn_app
adb shell settings get global always_on_vpn_lockdown

Te polecenia pokazują zainstalowaną sieć VPN, pakiet zawsze włączony oraz to, czy ustawiono blokadę. To obserwacje tylko do odczytu: jeśli wartości nie zgadzają się z tym, co twierdzi projekt, twierdzenie dotyczy interfejsu aplikacji, a nie stanu systemu.

Blokowanie może należeć do platformy

Android dokumentuje politykę blokującą połączenia, które nie korzystają z VPN. To egzekwowanie jest kontraktem platformy, a nie aplikacją, która w pętli ponawia próby połączeń. Przełącznik znajduje się w ustawieniach VPN urządzenia jako Blokuj połączenia bez VPN, a na urządzeniu zarządzanym właściciel może go włączyć dla całego profilu. Ta różnica ma znaczenie przy ocenie twierdzenia marketingowego: klient może pokazywać ikonę kłódki i agresywnie łączyć się ponownie, podczas gdy ruch bezpośredni nadal jest możliwy, albo objęte aplikacje mogą pozostać offline, bo system egzekwuje blokadę.

Ikonę kłódki rysuje aplikacja, więc dowodzi ona tylko, że aplikacja uważa się za połączoną. O tym, czy inna aplikacja straci dostęp do sieci, decyduje platforma, więc użytecznym sprawdzeniem jest obserwowanie, jak ta aplikacja zawodzi przy aktywnym tunelu.

Etykieta „zawsze włączone” ze sklepu z aplikacjami też nie zastępuje tego kontraktu. Zawsze włączone i blokada to ustawienia urządzenia, często stosowane przez właściciela, a ich zachowanie dla wykluczonych aplikacji definiuje platforma. Czytaj ustawienie, nie odznakę.

Cztery pytania do przeglądu projektu

Po pierwsze, kto wyraził zgodę: który pakiet, który profil i czy był to użytkownik, czy polityka urządzenia zarządzanego? Po drugie, o co poprosiła aplikacja: jakie trasy, jakie rodziny adresów, jakie aplikacje włączone lub wykluczone? Po trzecie, co się dzieje, gdy tunel jest niedostępny: system blokuje czy ruch wraca do sieci podkładowej? Po czwarte, co aplikacja robi z odbieranymi pakietami?

Czwarte pytanie to to, na które model uprawnień nie potrafi odpowiedzieć. Zgoda i interfejs TUN dowodzą, że aplikacja może odbierać ruch, a nie że go szyfruje, uwierzytelnia drugą stronę czy czysto się odtwarza. To właściwości implementacji i tam uczciwy przegląd spędza czas.

Zbędne żądanie root nie staje się uprawnione dlatego, że wynik nazywa się wyłącznikiem awaryjnym, a dialog zgody nie jest audytem bezpieczeństwa. Trzymaj trzy uprawnienia osobno, a każde twierdzenie staje się weryfikowalne.

Powiązane artykuły