Le root n'est pas ce qui permet à une application VPN Android de transporter du trafic, de bloquer les fuites ou de survivre à un redémarrage. Les gens résument tout cela par « l'application a la permission VPN », ce qui masque trois mécanismes distincts : un consentement accordé par l'utilisateur, une interface de paquets établie par le système et une politique de blocage de la plateforme qu'il n'appartient pas à l'application de définir. Examiner une conception VPN Android, c'est demander sur lequel des trois repose réellement une affirmation, car chacun a un propriétaire et un mode de défaillance différents.

Le consentement arrive par une activité système

VpnService.prepare() n'accorde rien. Elle renvoie un intent à l'activité de consentement du système lorsque le consentement manque, et l'application lance cette boîte de dialogue pour que l'utilisateur approuve le service. Démarrer le propre processus de l'application, ajouter une permission au manifeste ou afficher un écran personnalisé « activer le VPN » ne crée pas l'autorisation.

L'autorisation est aussi délimitée. Elle appartient à un paquet dans un profil utilisateur, donc la copie personnelle et la copie professionnelle sont des décisions distinctes, et le propriétaire d'un appareil peut préparer un profil géré différemment d'un profil personnel. Si la boîte de dialogue n'apparaît jamais et que prepare() renvoie null, le consentement existe déjà pour ce paquet dans ce profil ; ce n'est pas la preuve que l'application est fiable, seulement que l'autorisation est en place.

L'interface est une demande que le système exécute

Après le consentement, l'application décrit ce qu'elle veut avec VpnService.Builder : adresses, routes, serveurs DNS, MTU et, lorsque c'est pris en charge, les applications à inclure ou à exclure. establish() demande au système de créer l'interface de tunnel et d'y router le trafic correspondant. Le système détient la décision de routage ; l'application reçoit le descripteur de fichier et doit ensuite faire quelque chose d'utile avec les paquets.

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

Ce tableau est l'architecture en un seul endroit. L'application participe au traitement des paquets ; elle ne détient ni l'interface, ni la table de routage, ni le nombre de services qui peuvent s'exécuter.

La socket du tunnel doit échapper à son propre tunnel

La connexion qui transporte le trafic chiffré est elle-même une socket. Si elle est routée vers l'interface que l'application vient de créer, le tunnel dépend du tunnel et se bloque. VpnService.protect() lie cette socket au réseau sous-jacent pour qu'elle contourne la capture, et c'est pourquoi un client correct protège sa socket externe avant la première poignée de main.

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

Ces commandes montrent le réseau VPN installé, le paquet d'activation permanente et si le verrouillage est défini. Ce sont des observations en lecture seule : si les valeurs ne correspondent pas à ce que la conception affirme, l'affirmation porte sur l'interface de l'application et non sur l'état du système.

Le blocage peut appartenir à la plateforme

Android documente une politique qui bloque les connexions qui n'utilisent pas le VPN. Cette application est un contrat de la plateforme, pas une application qui réessaie des connexions en boucle. L'interrupteur se trouve dans les paramètres VPN de l'appareil sous le nom Bloquer les connexions sans VPN, et sur un appareil géré, le propriétaire peut l'activer pour tout le profil. La distinction compte quand vous évaluez une affirmation marketing : un client peut afficher une icône de cadenas et se reconnecter agressivement alors que le trafic direct reste possible, ou les applications couvertes peuvent rester hors ligne parce que le système applique le verrouillage.

L'icône de cadenas est dessinée par l'application, elle prouve donc seulement que l'application croit être connectée. La perte d'accès réseau d'une autre application est décidée par la plateforme, donc la vérification utile est de voir cette application échouer pendant que le tunnel est actif.

L'étiquette « toujours actif » d'une boutique d'applications ne remplace pas ce contrat non plus. L'activation permanente et le verrouillage sont des réglages de l'appareil, souvent appliqués par un propriétaire, et leur comportement pour les applications exclues est défini par la plateforme. Lisez le réglage, pas le badge.

Quatre questions pour une revue de conception

Premièrement, qui a consenti : quel paquet, quel profil, et était-ce l'utilisateur ou une politique d'appareil géré ? Deuxièmement, qu'a demandé l'application : quelles routes, quelles familles d'adresses, quelles applications incluses ou exclues ? Troisièmement, que se passe-t-il lorsque le tunnel est indisponible : le système bloque-t-il, ou le trafic retombe-t-il sur le réseau sous-jacent ? Quatrièmement, que fait l'application des paquets qu'elle reçoit ?

La quatrième question est celle à laquelle le modèle de permissions ne peut pas répondre. Le consentement et une interface TUN prouvent que l'application peut recevoir du trafic, pas qu'elle le chiffre, authentifie un pair ou se rétablit proprement. Ce sont des propriétés d'implémentation, et c'est là qu'une revue honnête passe son temps.

Une demande de root inutile ne devient pas légitime parce qu'on appelle le résultat un commutateur d'arrêt, et une boîte de dialogue de consentement n'est pas un audit de sécurité. Gardez les trois autorisations séparées et chaque affirmation devient vérifiable.

Articles similaires