Les Intents sont essentiels sur Android pour permettre la communication entre applications.
Ce sont des objets utilisés pour demander une action à un autre composant d’application.
Ils peuvent être utilisés dans plusieurs contextes :
-
Les activités
-
Les services
-
La diffusion de messages
Pour qu’un composant d’application soit accessible depuis une autre application, l’application qui expose ce composant doit définir android:exported
à true
.
Prenons l’exemple de l’application native Camera d’Android, qui permet de prendre des photos ou des vidéos.

Pour permettre aux autres applications d’utiliser cette fonctionnalité, Camera expose son composant Activity
en définissant android:exported="true"
. Ainsi, les autres applications peuvent l’appeler via l’Intent android.media.action.IMAGE_CAPTURE
, déclaré dans le <intent-filter>
de l’activité.
Exemple pratique
Pour illustrer comment une application utilise l’activité exposée par Camera, créons une application qui a besoin de récupérer une photo prise en direct.
On commence par déclarer notre activité :
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
Button homeButton = findViewById(R.id.home_button);
homeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("android.media.action.IMAGE_CAPTURE");
intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
startActivityForResult(intent, 42);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Utils.showDialog(this, intent);
}
}
Dans notre MainActivity
, nous avons ajouté un bouton, puis créé un listener qui lance un nouvel Intent lorsqu’on appuie dessus.
Cet Intent utilise une action implicite pour demander à toute application qui a déclaré <intent-filter>
avec android.media.action.IMAGE_CAPTURE
et android:exported="true"
dans son AndroidManifest.xml
de gérer la requête.
En lançant l’application et en regardant les logs, on voit comment Android résout l’Intent :

Il recherche toutes les applications installées qui exposent une activité avec cet intent-filter
.
Comme seule l’application Camera a déclaré cette action, Android retourne uniquement :com.android.camera2/com.android.camera.CaptureActivity
.
Exploitation
Deux types de vulnérabilités découlent des Intents :
1. Filtrage d’entrée insuffisant
Les Intents augmentent la surface d’attaque d’une application, un peu comme une API web.
Si une application reçoit des données mal filtrées depuis une autre, cela peut mener à des failles comme XSS, SQLi, voire une RCE.
2. Intent Hijacking
Il s’agit d’utiliser le même intent-filter
qu’une application légitime pour tromper l’utilisateur et intercepter des données sensibles.
Exemple :
-
L’application A dépend de l’application B pour l’authentification.
-
L’attaquant crée l’application C avec le même
intent-filter
que A. -
Quand B renvoie le token d’authentification, Android laisse l’utilisateur choisir entre A et C.
-
Si l’utilisateur sélectionne C, le token est envoyé à l’application malveillante.
Nous verrons l’Intent hijacking et les deep links dans un prochain article.
Voyons d’abord un exemple concret de faille due à un mauvais filtrage d’entrée.
Exemple d’attaque par données non filtrées
Notre application dépend d’une autre pour récupérer le nom de l’utilisateur.
Elle déclare donc une activité exportée avec deux intent-filter
:

L’application récupère la donnée envoyée par l’Intent et l’affiche dans une page web intégrée :
String data = getIntent().getStringExtra("data");
if (data == null) {
data = "Invité";
}
WebView webView = findViewById(R.id.webview);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
String userInput = "Bienvenue
" +
"" + data + "
";
webView.loadData(userInput, "text/html", "UTF-8");
Si aucune donnée n’est reçue, le nom affiché par défaut sera Invité :

Application malveillante
Créons maintenant une application qui envoie une donnée piégée :

-
Traitez toute donnée reçue via un Intent externe comme potentiellement malveillante.
-
Filtrez et validez toutes les entrées avant de les utiliser.
-
Évitez d’exposer des activités inutilement (
android:exported="false"
par défaut).
Même les activités non exportées peuvent devenir une cible si elles sont déclenchées par d’autres activités exportées via des Intent contrôlables par l’utilisateur.
La surface d’attaque peut alors couvrir toutes les activités déclarées dans le AndroidManifest.xml
.