VPN Android senza root: a chi appartengono consenso, rotte e blocco
Il consenso, l'interfaccia TUN e la politica di blocco del sistema sono tre autorizzazioni diverse. Individua quale componente possiede ciascuna prima di esaminare un'app VPN Android.
Il root non è ciò che permette a un'app VPN Android di trasportare traffico, bloccare fughe o sopravvivere a un riavvio. Le persone riassumono tutto questo come «l'app ha il permesso VPN», il che nasconde tre meccanismi distinti: un consenso concesso dall'utente, un'interfaccia di pacchetti stabilita dal sistema e una politica di blocco della piattaforma che non spetta all'app definire. Esaminare un progetto VPN Android significa chiedere su quale dei tre si basi davvero un'affermazione, perché ognuno ha un proprietario e una modalità di guasto diversi.
Il consenso arriva tramite un'attività di sistema
VpnService.prepare() non concede nulla. Restituisce un intent all'attività di consenso del sistema quando manca il consenso, e l'app avvia quel dialogo affinché l'utente approvi il servizio. Avviare il processo dell'app stessa, aggiungere un permesso al manifest o mostrare una schermata personalizzata «attiva VPN» non crea l'autorizzazione.
L'autorizzazione è anche circoscritta. Appartiene a un pacchetto in un profilo utente, quindi la copia personale e la copia di lavoro sono decisioni separate, e il proprietario di un dispositivo può preparare un profilo gestito in modo diverso da uno personale. Se il dialogo non compare mai e prepare() restituisce null, il consenso esiste già per quel pacchetto in quel profilo; non è prova che l'app sia affidabile, solo che l'autorizzazione c'è.
L'interfaccia è una richiesta che il sistema soddisfa
Dopo il consenso, l'app descrive ciò che vuole con VpnService.Builder: indirizzi, rotte, server DNS, MTU e, dove supportato, le applicazioni da includere o escludere. establish() chiede al sistema di creare l'interfaccia del tunnel e di instradarvi il traffico corrispondente. Il sistema possiede la decisione di instradamento; l'app riceve il descrittore di file e poi deve fare qualcosa di utile con i pacchetti.
| 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 |
Quella tabella è l'architettura in un solo posto. L'app partecipa alla gestione dei pacchetti; non possiede l'interfaccia, la tabella di instradamento o il numero di servizi che possono essere eseguiti.
Il socket del tunnel deve sfuggire al proprio tunnel
La connessione che trasporta il traffico cifrato è essa stessa un socket. Se viene instradata di nuovo nell'interfaccia appena creata dall'app, il tunnel dipende dal tunnel e si blocca. VpnService.protect() lega quel socket alla rete sottostante perché aggiri la cattura, ed è per questo che un client corretto protegge il proprio socket esterno prima del primo 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
Questi comandi mostrano la rete VPN installata, il pacchetto di attivazione permanente e se il blocco è impostato. Sono osservazioni di sola lettura: se i valori non corrispondono a ciò che il progetto afferma, l'affermazione riguarda l'interfaccia dell'app e non lo stato del sistema.
Il blocco può appartenere alla piattaforma
Android documenta una politica che blocca le connessioni che non usano la VPN. Quell'applicazione è un contratto della piattaforma, non un'app che ritenta le connessioni in un ciclo. L'interruttore si trova nelle impostazioni VPN del dispositivo come Blocca connessioni senza VPN, e su un dispositivo gestito il proprietario può attivarlo per l'intero profilo. La distinzione conta quando valuti un'affermazione di marketing: un client può mostrare un'icona a lucchetto e riconnettersi in modo aggressivo mentre il traffico diretto resta possibile, oppure le app coperte possono restare offline perché il sistema applica il blocco.
L'icona a lucchetto è disegnata dall'app, quindi dimostra solo che l'app crede di essere connessa. Se un'altra app perde l'accesso alla rete lo decide la piattaforma, quindi il controllo utile è vedere quell'app fallire mentre il tunnel è attivo.
Nemmeno l'etichetta «sempre attivo» di un app store sostituisce quel contratto. L'attivazione permanente e il blocco sono impostazioni del dispositivo, spesso applicate dal proprietario, e il loro comportamento per le app escluse è definito dalla piattaforma. Leggi l'impostazione, non il badge.
Quattro domande per una revisione del progetto
Primo, chi ha acconsentito: quale pacchetto, quale profilo, e se è stato l'utente o una politica di dispositivo gestito. Secondo, che cosa ha richiesto l'app: quali rotte, quali famiglie di indirizzi, quali app incluse o escluse. Terzo, che cosa succede quando il tunnel non è disponibile: il sistema blocca o il traffico ricade sulla rete sottostante? Quarto, che cosa fa l'app con i pacchetti che riceve.
La quarta domanda è quella a cui il modello dei permessi non può rispondere. Il consenso e un'interfaccia TUN dimostrano che l'app può ricevere traffico, non che lo cifri, autentichi un pari o si riprenda in modo pulito. Sono proprietà dell'implementazione, ed è lì che una revisione onesta passa il suo tempo.
Una richiesta di root superflua non diventa legittima perché si chiama il risultato interruttore di sicurezza, e un dialogo di consenso non è un audit di sicurezza. Tieni separate le tre autorizzazioni e ogni affermazione diventa verificabile.