Root is niet wat een Android-VPN-app in staat stelt verkeer te dragen, lekken te blokkeren of een herstart te overleven. Mensen vatten dat alles samen als „de app heeft VPN-toestemming“, wat drie afzonderlijke mechanismen verbergt: een toestemming van de gebruiker, een pakketinterface die het systeem opzet, en een blokkeringsbeleid van het platform dat niet aan de app is om te bepalen. Een Android-VPN-ontwerp beoordelen betekent vragen op welke van de drie een bewering werkelijk rust, want elk heeft een andere eigenaar en een andere faalmodus.

Toestemming komt via een systeemactiviteit

VpnService.prepare() verleent niets. Het geeft een intent terug naar de systeemtoestemmingsactiviteit wanneer toestemming ontbreekt, en de app start die dialoog zodat de gebruiker de dienst kan goedkeuren. Het eigen proces van de app starten, een machtiging aan het manifest toevoegen of een eigen scherm „VPN inschakelen“ tonen maakt de toestemming niet aan.

De toestemming is ook afgebakend. Ze hoort bij een pakket in een gebruikersprofiel, dus de persoonlijke kopie en de werkkopie zijn aparte beslissingen, en een apparaateigenaar kan een beheerd profiel anders voorbereiden dan een persoonlijk. Als de dialoog nooit verschijnt en prepare() null teruggeeft, bestaat de toestemming al voor dat pakket in dat profiel; dat is geen bewijs dat de app betrouwbaar is, alleen dat de toestemming er is.

De interface is een verzoek dat het systeem vervult

Na toestemming beschrijft de app wat hij wil met VpnService.Builder: adressen, routes, DNS-servers, MTU en, waar ondersteund, de apps die moeten worden opgenomen of uitgesloten. establish() vraagt het systeem de tunnelinterface aan te maken en het bijbehorende verkeer erheen te leiden. Het systeem bezit de routeringsbeslissing; de app ontvangt de bestandsdescriptor en moet daarna iets nuttigs met de pakketten doen.

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

Die tabel is de architectuur op één plek. De app doet mee aan pakketafhandeling; hij bezit niet de interface, de routetabel of het aantal diensten dat mag draaien.

De tunnelsocket moet aan zijn eigen tunnel ontsnappen

De verbinding die het versleutelde verkeer draagt, is zelf een socket. Als die terug wordt gerouteerd naar de interface die de app net heeft gemaakt, hangt de tunnel van de tunnel af en stokt. VpnService.protect() bindt die socket aan het onderliggende netwerk zodat hij de opvang omzeilt, en daarom beschermt een correcte client zijn buitenste socket vóór de eerste handshake.

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

Deze commando's tonen het geïnstalleerde VPN-netwerk, het pakket voor altijd aan en of de vergrendeling is ingesteld. Het zijn alleen-lezen waarnemingen: als de waarden niet overeenkomen met wat het ontwerp beweert, gaat de bewering over de interface van de app en niet over de toestand van het systeem.

Blokkering kan van het platform zijn

Android documenteert een beleid dat verbindingen blokkeert die de VPN niet gebruiken. Die handhaving is een platformcontract, niet een app die verbindingen in een lus opnieuw probeert. De schakelaar staat in de VPN-instellingen van het apparaat als Verbindingen zonder VPN blokkeren, en op een beheerd apparaat kan de eigenaar hem voor het hele profiel aanzetten. Het onderscheid is belangrijk bij het beoordelen van een marketingbewering: een client kan een slotpictogram tonen en agressief opnieuw verbinden terwijl direct verkeer nog mogelijk is, of gedekte apps kunnen offline blijven omdat het systeem de vergrendeling handhaaft.

Het slotpictogram wordt door de app getekend, dus het bewijst alleen dat de app gelooft dat hij verbonden is. Of een andere app zijn netwerktoegang verliest, beslist het platform, dus de nuttige controle is die app te zien falen terwijl de tunnel aan staat.

Een „altijd aan“-label uit de appwinkel vervangt dat contract ook niet. Altijd aan en vergrendeling zijn apparaatinstellingen, vaak toegepast door een eigenaar, en hun gedrag voor uitgesloten apps wordt door het platform bepaald. Lees de instelling, niet de badge.

Vier vragen voor een ontwerpreview

Ten eerste, wie heeft toegestemd: welk pakket, welk profiel, en was het de gebruiker of een beleid voor beheerde apparaten? Ten tweede, wat heeft de app aangevraagd: welke routes, welke adresfamilies, welke opgenomen of uitgesloten apps? Ten derde, wat gebeurt er als de tunnel niet beschikbaar is: blokkeert het systeem, of valt het verkeer terug op het onderliggende netwerk? Ten vierde, wat doet de app met de pakketten die hij ontvangt?

De vierde vraag is degene die het machtigingsmodel niet kan beantwoorden. Toestemming en een TUN-interface bewijzen dat de app verkeer kan ontvangen, niet dat hij het versleutelt, een tegenpartij authenticeert of schoon herstelt. Dat zijn implementatie-eigenschappen, en daar brengt een eerlijke review zijn tijd door.

Een onnodig root-verzoek wordt niet legitiem door het resultaat een kill switch te noemen, en een toestemmingsdialoog is geen beveiligingsaudit. Houd de drie machtigingen gescheiden en elke bewering wordt controleerbaar.

Gerelateerde artikelen