Android-VPN utan root: kven eig samtykket, rutene og blokkeringa
Samtykke, TUN-grensesnittet og blokkeringspolitikken til systemet er tre ulike løyve. Spor kva komponent som eig kvar av dei, før du vurderer ein Android-VPN-app.
Root er ikkje det som gjer at ein Android-VPN-app kan frakte trafikk, blokkere lekkasjar eller overleve ein omstart. Folk summerer alt dette som „appen har VPN-løyve“, noko som skjuler tre skilde mekanismar: eit samtykke frå brukaren, eit pakkegrensesnitt systemet opprettar, og ein blokkeringspolitikk på plattformen som ikkje er appen sitt å definere. Å vurdere eit Android-VPN-design tyder å spørje kva av dei tre ein påstand faktisk kviler på, fordi kvar har ein annan eigar og ein annan feilmodus.
Samtykke kjem gjennom ein systemaktivitet
VpnService.prepare() gir ingenting. Det returnerer ein intent til samtykkeaktiviteten til systemet når samtykke manglar, og appen startar dialogen slik at brukaren kan godkjenne tenesta. Å starte appen sin eigen prosess, leggje til eit løyve i manifestet eller vise ein eigen „slå på VPN“-skjerm skaper ikkje løyvet.
Løyvet er også avgrensa. Det høyrer til ein pakke i ein brukarprofil, så den personlege kopien og arbeidskopien er separate avgjerder, og ein einingseigar kan førebu ein styrt profil annleis enn ein personleg. Viss dialogen aldri blir vist og prepare() returnerer null, finst samtykket allereie for den pakken i den profilen; det er ikkje prov for at appen er påliteleg, berre at løyvet er på plass.
Grensesnittet er ein førespurnad systemet oppfyller
Etter samtykket skildrar appen kva han vil ha med VpnService.Builder: adresser, ruter, DNS-tenarar, MTU og, der det er støtta, appane som skal takast med eller haldast utanfor. establish() ber systemet opprette tunnelgrensesnittet og leie den samsvarande trafikken inn i det. Systemet eig rutingsavgjerda; appen får fildeskriptoren og må deretter gjere noko nyttig med pakkane.
| What you observe | Who actually owns it |
|---|---|
| VPN consent dialog | The system, triggered by prepare() |
| Routes, DNS and app lists | The app requests them; the system applies them |
| One active VPN per profile | The platform; a new service replaces the old one |
| Always-on and block-without-VPN | Device policy enforced by the platform |
Den tabellen er arkitekturen på éin stad. Appen deltek i pakkehandtering; han eig ikkje grensesnittet, rutetabellen eller talet på tenester som kan køyre.
Tunnelsocketen må rømme frå sin eigen tunnel
Sambandet som fraktar den krypterte trafikken, er sjølv ein socket. Viss det blir ruta tilbake til grensesnittet appen nettopp oppretta, er tunnelen avhengig av tunnelen og stoppar. VpnService.protect() bind socketen til det underliggjande nettet slik at han går utanom opptaket, og difor vernar ein korrekt klient den ytre socketen før det første handtrykket.
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
Desse kommandoane viser det installerte VPN-nettet, pakken for alltid på og om låsing er sett. Dei er berre leseobservasjonar: viss verdiane ikkje stemmer med det designet hevdar, gjeld påstanden grensesnittet til appen og ikkje tilstanden til systemet.
Blokkering kan høyre til plattformen
Android dokumenterer ein politikk som blokkerer tilkoplingar som ikkje brukar VPN. Den handhevinga er ein plattformkontrakt, ikkje ein app som gentek tilkoplingsforsøk i ei løkke. Brytaren ligg i VPN-innstillingane til eininga som Blokker tilkoplingar utan VPN, og på ei styrt eining kan eigaren slå han på for heile profilen. Skilnaden tel når du vurderer ein marknadsføringspåstand: ein klient kan vise eit hengelåsikon og kople til på nytt aggressivt medan direkte trafikk framleis er mogleg, eller dekte appcontainerar kan halde fram som fråkopla fordi systemet handhevar låsinga.
Hengelåsikonet blir teikna av appen, så det provar berre at appen trur han er tilkopla. Om ein annan app misser nettverkstilgangen, blir avgjort av plattformen, så den nyttige kontrollen er å sjå den appen feile medan tunnelen er oppe.
Ei „alltid på“-merkelapp frå appbutikken erstattar heller ikkje den kontrakten. Alltid på og låsing er eininginnstillingar, ofte brukte av ein eigar, og åtferda deira for utelatne appcontainerar blir definert av plattformen. Les innstillinga, ikkje merket.
Fire spørsmål for ein designgjennomgang
For det første, kven samtykte: kva pakke, kva profil, og var det brukaren eller ein politikk for styrte einingar? For det andre, kva bad appen om: kva ruter, kva adressefamiliar, kva appcontainerar som vart tekne med eller haldne utanfor? For det tredje, kva skjer når tunnelen ikkje er tilgjengeleg: blokkerer systemet, eller fell trafikken tilbake til det underliggjande nettet? For det fjerde, kva gjer appen med pakkane han mottar?
Det fjerde spørsmålet er det løyvesmodellen ikkje kan svare på. Samtykke og eit TUN-grensesnitt provar at appen kan ta imot trafikk, ikkje at han krypterer han, autentiserer ein motpart eller kjem seg reint. Det er implementeringseigenskapar, og det er der ein ærleg gjennomgang brukar tida si.
Ein unødvendig root-førespurnad blir ikkje legitim av å kalle resultatet ein kill switch, og ein samtykkedialog er ikkje ein tryggleiksrevisjon. Hald dei tre løyva skilde, og kvar påstand blir kontrollerbar.