Neutron, notre moteur d’IA, a obtenu un score de 96,75 % sur le benchmark CyberGym de l’UC Berkeley. En savoir plus

Sécurité

Sécurité

Qu'est-ce que le SSL pinning ? Guide Android avec OkHttp

Mettez en œuvre le SSL pinning sur Android avec Network Security Config, OkHttp et Retrofit, puis testez-le et faites tourner les pins en toute sécurité. Inclut des exemples avec des bibliothèques anciennes.

SSL pinning sur Android (épinglage de certificat et de clé publique)

La sécurisation des communications entre une application Android et son backend commence par TLS. TLS protège les données en transit en chiffrant la connexion, en authentifiant le serveur et en empêchant l'envoi de trafic sensible en clair. Dans une configuration Android standard, l'application s'appuie sur le magasin de confiance de la plateforme et sur la validation normale des certificats pour décider si un certificat de serveur doit être approuvé.

Le pinning ajoute une restriction de confiance supplémentaire par-dessus ce socle. Au lieu d'accepter toute chaîne de certificats validée par le modèle de confiance habituel, l'application n'accepte que les chaînes qui contiennent un élément de clé précis et attendu. Cela peut rendre les attaques de l'homme du milieu plus difficiles dans certains scénarios, mais introduit aussi un risque opérationnel : un changement de certificat, une migration d'autorité de certification ou une rotation de clés peut interrompre des connexions légitimes si le pinning est trop rigide ou mal géré. Les recommandations d'Android sur l'épinglage de certificat sont prudentes sur ce point : elles précisent que le pinning n'est généralement pas recommandé pour la plupart des applications, car des changements de configuration côté serveur peuvent rompre la connectivité tant que le client n'est pas mis à jour.

Ce guide explique ce que signifie le SSL pinning sur Android, quand il est utile, contre quoi il ne protège pas, les principales options de mise en œuvre, comment le valider en toute sécurité et comment l'exploiter en production sans transformer la rotation des certificats en panne. Il inclut aussi des exemples avec HttpsURLConnection, OkHttp, Retrofit, Volley et Picasso pour les équipes qui travaillent à la fois avec des piles réseau Android modernes et anciennes.

Comparaison de la confiance sur Android : l'AC par défaut accepte plusieurs chaînes de certificats ; la confiance épinglée n'accepte que les chaînes contenant la clé épinglée et rejette les autres.

Table des matières

  1. Ce que signifie le SSL pinning sur Android
  2. SSL pinning, TLS pinning et certificate pinning
  3. Contre quoi le pinning ne protège pas
  4. Modèle de menace : quand le pinning est utile
  5. Options de pinning sur Android
  6. Exemples de mise en œuvre
  7. Comment vérifier que le SSL pinning fonctionne
  8. Exploiter le pinning en production en toute sécurité
  9. Pour aller plus loin
  10. FAQ

Ce que signifie le SSL pinning sur Android

Dans une configuration Android standard, une application fait confiance aux certificats de serveur qui sont validés par le magasin de confiance de la plateforme. Le SSL pinning ajoute une restriction supplémentaire à ce modèle : la connexion n'est acceptée que si la chaîne de certificats contient un élément de clé précis et attendu pour le domaine cible.

Sur Android, cela se fait généralement en épinglant des hachages de la clé publique du certificat, ce que l'on appelle aussi le pinning SPKI. Au lieu de faire confiance à toute chaîne valide ancrée dans une autorité de certification généralement approuvée, l'application restreint la confiance aux chaînes qui incluent l'une des clés publiques épinglées.

Concrètement, cela signifie que l'application ne vérifie pas seulement qu'un certificat est valide, mais aussi qu'il répond à une attente de confiance plus précise, définie par l'application elle-même. Le CertificatePinner d'OkHttp suit la même idée en validant la chaîne de certificats du serveur par rapport à des hachages de clés publiques épinglés.

SSL pinning, TLS pinning et certificate pinning

« SSL pinning » reste l'expression que la plupart des gens utilisent, mais en pratique elle désigne généralement l'épinglage de certificat TLS ou de clé publique. Dans les recommandations de sécurité actuelles d'Android, le pinning est décrit en termes de hachages de clés publiques. Tout au long de ce guide, les termes SSL pinning, TLS pinning, certificate pinning et public key pinning sont employés comme les praticiens les recherchent et en parlent habituellement, tout en conservant une signification technique précise.

Contre quoi le pinning ne protège pas

Le pinning ne remplace pas une validation TLS correcte. Si une application utilise un HostnameVerifier non sécurisé ou un unsafe X509TrustManager, elle peut rester vulnérable à l'usurpation d'identité et à l'interception. Android documente ces deux cas comme des risques de sécurité explicites, car ils peuvent amener l'application à accepter des connexions malveillantes ou invalides.

Le pinning ne corrige pas non plus les vulnérabilités côté serveur, les identifiants divulgués, une mauvaise gestion des sessions, des API non sécurisées ni l'exposition de données sensibles ailleurs dans l'application. C'est un contrôle de sécurité du transport, pas une stratégie complète de sécurité des applications mobiles. C'est l'une des raisons pour lesquelles il faut considérer le pinning comme une partie d'un modèle de sécurité Android plus large, et non comme une simple case de durcissement à cocher.

Modèle de menace : quand le pinning est utile

La documentation d'Android explique clairement le scénario central : par défaut, les applications font confiance à de nombreuses autorités de certification préinstallées, et si l'une d'elles émettait un certificat frauduleux, l'application pourrait être exposée à un attaquant positionné sur le chemin du trafic. Le pinning réduit cette confiance en exigeant que la chaîne de certificats contienne l'une des clés publiques épinglées. OkHttp décrit la même protection comme une défense contre les attaques visant les autorités de certification et contre les autorités de certification d'interception, connues ou non de l'utilisateur.

Le pinning est donc plus pertinent lorsqu'une équipe veut un contrôle plus strict sur les chaînes de confiance acceptées pour un backend donné. Il est généralement plus facile à justifier lorsque le backend est stable, que le cycle de vie des certificats est étroitement géré et que la charge opérationnelle de la rotation a déjà été planifiée. Même dans ce cas, le pinning est un contrôle très contraignant, qu'il ne faut pas introduire à la légère. Android le traite comme une mesure opérationnellement fragile, et la documentation d'OkHttp est assez explicite pour le qualifier ainsi : « Certificate Pinning is Dangerous! because it limits certificate updates and adds operational complexity.

Options de pinning sur Android

Dans les bases de code Android récentes, le pinning est plus souvent géré via Android Network Security Configuration (voir l'exemple dans la section suivante) , qui prend en charge l'épinglage de certificat, les pins de secours, l'expiration des pins, les ancres de confiance personnalisées et les surcharges de débogage dans un fichier de configuration déclaratif. Cela centralise les décisions de confiance au lieu de répartir la gestion de TLS entre plusieurs bibliothèques. Si l'application utilise directement OkHttp, CertificatePinner reste l'option principale au niveau du client. Comme Retrofit repose sur un client HTTP, le comportement du pinning dans les configurations Retrofit dépend du client sous-jacent configuré, généralement OkHttp.

Dans les bases de code Android plus anciennes, le pinning peut encore reposer sur une gestion TLS personnalisée dans HttpsURLConnection, Volley ou les intégrations Picasso. Ces exemples peuvent rester utiles comme références historiques ou pour maintenir des applications héritées, mais ils doivent être considérés comme d'anciens modèles d'implémentation plutôt que comme le choix par défaut pour de nouveaux projets. Pour le pinning sur Android, OWASP MASTG présente Network Security Configuration comme l'approche privilégiée et recommandée, tout en avertissant que le pinning personnalisé fondé sur un TrustManager est une méthode de bas niveau, sujette aux erreurs si elle n'est pas implémentée avec soin

Approche Prise en charge du pinning Charge de maintenance Principal piège Cas d'usage idéal
Android Network Security Configuration Oui Plus faible Exige une configuration soignée des domaines et du débogage La plupart des applications Android modernes
OkHttp CertificatePinner Oui Moyenne La rotation et la couverture des noms d'hôte doivent être planifiées Applications qui utilisent déjà OkHttp directement
Retrofit avec un client OkHttp configuré Oui Moyenne Retrofit hérite du comportement du client ; le pinning n'est pas distinct Applications basées sur Retrofit
Configuration de confiance personnalisée avec HttpsURLConnection Possible Plus élevée Facile de trop personnaliser la gestion de TLS Maintenance d'anciennes applications uniquement
Configuration TLS personnalisée avec Volley Possible Plus élevée Plus difficile à garder centralisée Maintenance d'anciennes applications uniquement
Configuration personnalisée du downloader avec Picasso Possible Plus élevée Ancien modèle d'intégration Maintenance d'anciennes applications uniquement

Cette comparaison reflète les recommandations actuelles d'Android, la documentation d'OkHttp et la différence pratique entre une configuration déclarative au niveau de la plateforme et une personnalisation plus ancienne de la confiance propre à chaque bibliothèque.

Exemples de mise en œuvre

Le pinning peut être mis en œuvre de différentes façons selon la pile réseau Android utilisée. Pour un nouveau projet, commencez par Network Security Configuration ou par une configuration OkHttp moderne. Les exemples de bibliothèques ci-dessous se comprennent mieux comme des modèles de référence anciens, destinés aux équipes qui maintiennent encore des piles plus anciennes.

Recommandation moderne avant les exemples anciens

Si vous développez aujourd'hui une nouvelle application Android, commencez par Android Network Security Configuration pour une confiance et un pinning déclaratifs, ou par OkHttp CertificatePinner si votre pile réseau est déjà centrée sur OkHttp. Android prend en charge l'épinglage de clé publique via pin-set, prend en charge les pins de secours, autorise une date d'expiration facultative et inclut des surcharges réservées au débogage pour que les équipes puissent tester en toute sécurité sans affaiblir les builds de production.

Exemple de pinning avec Android Network Security Configuration (NSC), déclaratif

Créez res/xml/network_security_config.xml :

    <?xml version="1.0" encoding="utf-8"?>
<network-security-config>

    <!-- Apply rules to a specific domain (and optionally its subdomains) -->
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">example.com</domain>

        <!-- Public-key pins (SHA-256 of SPKI), with an expiration date -->
        <pin-set expiration="2027-12-31">
            <!-- Primary pin -->
            <pin digest="SHA-256">afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=</pin>

            <!-- Backup pin (rotate keys/certs safely) -->
            <pin digest="SHA-256">BASE64_SHA256_BACKUP_SPKI_PIN_HERE=</pin>
        </pin-set>

        <!-- Optional: customize which CAs you trust for this domain -->
        <trust-anchors>
            <certificates src="system" />
            <!-- If you also need a private CA bundled with the app: -->
            <!-- <certificates src="@raw/my_private_ca" /> -->
        </trust-anchors>
    </domain-config>

    <!-- Optional (debug builds): allow user-added / debug CAs without weakening release -->
    <debug-overrides>
        <trust-anchors>
            <certificates src="user" />
            <!-- or a dedicated debug CA -->
            <!-- <certificates src="@raw/debug_ca" /> -->
        </trust-anchors>
    </debug-overrides>

</network-security-config>

Points clés : pin-set prend en charge plusieurs pins (principal + secours) et une date d'expiration (au format yyyy-MM-dd), après laquelle le pinning est désactivé si vous ne mettez pas la configuration à jour. Branchez-le dans AndroidManifest.xml

<application
    android:networkSecurityConfig="@xml/network_security_config"
    android:usesCleartextTraffic="false"
    ... >
</application>

Épinglage de certificat sur Android avec HttpsURLConnection

    CertificateFactory cf = CertificateFactory.getInstance("X.509");

    // Generate the certificate using the certificate file under res/raw/cert.cer
    InputStream caInput = new BufferedInputStream(getResources().openRawResource(R.raw.cert));
    Certificate ca = cf.generateCertificate(caInput);
    caInput.close();

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    // Tell the URLConnection to use a SocketFactory from our SSLContext
    URL url = new URL("https://example.com/faq/");
    HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());
    InputStream in = urlConnection.getInputStream();
    theString = readInputStream(in);
    CertificateFactory cf = CertificateFactory.getInstance("X.509");

Épinglage de certificat sur Android avec OkHTTP

    //okhttp version 3.x

    public CertificatePinning()
    {
        // We add the public key of our trusted server hashed and encoded base64
        client = new OkHttpClient.Builder().certificatePinner(new CertificatePinner.Builder()
        .add("https://example.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=").build()).build();
    }

    public void run() throws Exception
    {
        Request request = new Request.Builder().url("https://example.com/faq").build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

    /**
    * response.handshake() contains the TLS handshake of the connection that carried this response, or null if the response
    * was received without TLS.
    */
        if(response.handshake())
        {
            for (Certificate certificate : response.handshake().peerCertificates())
            {
                //Pin returns SHA-256 hash of the public key
                String caPin = CertificatePinner.pin(certificate);

                // then you we to check the hash value and apply the corresponding action
            }
        }
    }

Épinglage de certificat sur Android avec Retrofit

    // Use the steps above to create OkHttpClient and set the custom client when building adapter
    Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://example.com")
    .addConverterFactory(GsonConverterFactory.create())
    .client(client)
    .build();
  Volley:

    CertificateFactory cf = CertificateFactory.getInstance("X.509");

    // Generate the certificate using the certificate file under res/raw/cert.cer
    InputStream caInput = new BufferedInputStream(getResources().openRawResource(R.raw.cert));
    Certificate ca = cf.generateCertificate(caInput);
    caInput.close();

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore trusted = KeyStore.getInstance(keyStoreType);
    trusted.load(null, null);
    trusted.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(trusted);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    SSLSocketFactory sf = context.getSocketFactory();
    mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(), new HurlStack(null, sf));

Épinglage de certificat sur Android avec Picasso

    CertificateFactory cf = CertificateFactory.getInstance("X.509");

    // Certificate file is under res/raw/cert.cer
    InputStream caInput = new BufferedInputStream(getResources().openRawResource(R.raw.cert));
    Certificate ca = cf.generateCertificate(caInput);
    caInput.close();

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    OkHttpClient okHttpClient = new OkHttpClient();
    okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
    OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
    Picasso.Builder builder = new Picasso.Builder(context);
    builder.downloader(okHttpDownloader);
    Picasso sPicasso = builder.build();

Comment vérifier que le SSL pinning fonctionne (sans pénaliser les utilisateurs)

Pour vérifier le SSL pinning dans des applications Android et iOS, configurez un proxy comme Burp Suite ou mitmproxy et confirmez que l'application bloque l'interception du trafic alors qu'elle fait confiance au certificat de l'AC du proxy. Cela prouve que le pinning empêche les attaques de l'homme du milieu.

Prérequis :

  1. Installez mitmproxy : pip install mitmproxy.
  2. Exécutez mitmdump -p 8080 (ou mitmproxy pour l'interface) ; notez votre IP (par exemple avec ifconfig ou ip addr).
  3. Un Android rooté ou un iOS jailbreaké est recommandé pour une confiance complète ; fonctionne sur les émulateurs et les simulateurs.

Étapes sous Android

  1. Configurez le proxy Wi-Fi de l'appareil sur :8080 ; testez avec HTTPS dans le navigateur (le trafic doit passer par le proxy).
  2. Visitez http://mitm.it/?mode=android dans le navigateur ; téléchargez et installez l'AC utilisateur.
  3. Pour la confiance au niveau système (nécessaire pour la plupart des applications) : openssl x509 -inform PEM -subject_hash_old -in ~/.mitmproxy/mitmproxy-ca-cert.pem | head -1 → .0 ; adb push .0 /system/etc/security/cacerts/ ; adb shell chmod 644 /system/etc/security/cacerts/.0 ; redémarrez.
  4. Déclenchez les appels réseau de l'application — s'il n'y a aucun flux dans mitmproxy/mitmdump et des erreurs SSL dans adb logcat | grep -i ssl — le pinning est actif.

Validation :

Le bon fonctionnement normal de l'application sans proxy confirme que le problème vient du pinning, et non de la configuration. Si le trafic est intercepté, il n'y a pas de pinning (ou utilisez des outils de contournement comme objection pour confirmer).

Essayez de le faire au démarrage de l'application, mais aussi ensuite, car certaines applications ne vérifient qu'au cours d'actions précises et ignorent la vérification par la suite.

Exploiter le pinning en production en toute sécurité (rotation, pins de secours, déploiement)

Le principal risque du pinning en production est la rotation des certificats ou des clés. Android recommande explicitement d'inclure toujours une clé de secours, afin que la connectivité de l'application ne soit pas perdue si vous devez changer de clés ou d'autorité de certification. Il prend aussi en charge une date d'expiration pour les pins, ce qui peut réduire le risque de panne indéfinie dans les versions obsolètes de l'application, au prix toutefois de la perte de protection de la connexion une fois les pins expirés.

OkHttp est tout aussi direct sur la charge opérationnelle : le pinning limite la capacité de l'équipe serveur à mettre à jour les certificats et à migrer d'une autorité de certification à une autre. C'est pourquoi le pinning doit être déployé comme une fonctionnalité de production, et non simplement fusionné comme un nettoyage de code. Un déploiement raisonnable consiste à commencer par les builds internes, puis la bêta, puis un pourcentage limité de la production, et seulement ensuite le déploiement complet, une fois le comportement des certificats, la supervision et les plans de repli validés. Cette recommandation de déploiement progressif est une recommandation opérationnelle fondée sur les contraintes documentées par Android et OkHttp.

Lorsque le pinning échoue en production, l'application doit échouer d'une manière compréhensible et diagnostiquable. Au minimum, définissez le message présenté à l'utilisateur, les champs de journalisation, les seuils d'alerte et le circuit de tri du support. Un échec de pin est différent d'un délai d'attente générique ou d'une situation hors ligne : il ne doit donc pas disparaître dans la même catégorie d'erreurs.

L'inspection TLS en entreprise et les portails captifs méritent aussi une décision de politique explicite. Comme le pinning restreint la confiance à des éléments de clé attendus, les environnements qui remplacent les certificats de serveur peuvent faire échouer le pinning par conception. Les équipes doivent décider de ce comportement délibérément avant le déploiement, plutôt que de le découvrir pendant celui-ci. Pour un exemple technique d'analyse du trafic dans des environnements avec pinning sans désactiver celui-ci, consultez notre article Universal bypass of SSL Pinning ... from theory to a full working PoC with LLDB.

FAQ

Le SSL pinning sur Android en vaut-il la peine ?

Il peut en valoir la peine, mais seulement lorsque le backend, le processus de livraison et le cycle de vie des certificats sont assez matures pour le supporter. Les recommandations officielles d'Android mettent explicitement en garde : le pinning de certificat n'est généralement pas recommandé pour de nombreuses applications, car des changements de certificat côté backend peuvent rompre la connectivité tant que le client n'est pas mis à jour. Lorsque des équipes choisissent le pinning, Android recommande des pins de secours et une fenêtre d'expiration courte.

Quelle est la différence entre l'épinglage de certificat et l'épinglage de clé publique ?

Dans les recommandations actuelles d'Android, le pinning s'exprime sous forme de hachages de la clé publique du certificat plutôt que sous forme d'une comparaison brute du fichier de certificat complet. Le CertificatePinner d'OkHttp documente lui aussi un pinning fondé sur SPKI. Qu'est-ce qui casse lorsque les certificats sont renouvelés ? Si la nouvelle chaîne de certificats ne contient plus l'une des clés épinglées, l'application peut perdre la connectivité jusqu'à la mise à jour des pins, ou jusqu'à ce qu'un pin de secours soit déjà présent. C'est pourquoi Android recommande des clés de secours et prend en charge l'expiration facultative des pins.

Android Network Security Configuration prend-il en charge le pinning ?

Oui. Android prend en charge l'épinglage de certificat via les pin-set entries de Network Security Configuration, notamment plusieurs pins, des pins de secours, l'expiration, des ancres de confiance personnalisées et des surcharges réservées au débogage.

Retrofit gère-t-il le pinning par lui-même ?

Non. Retrofit transforme votre API HTTP en interface Java ou Kotlin, et le comportement du pinning provient du client sous-jacent configuré, tel qu'OkHttp.

Comment tester le pinning sans affaiblir la sécurité de la production ?

Utilisez des tests contrôlés en préproduction, validez à la fois les cas de succès et de non-correspondance, et utilisez la prise en charge de la configuration de débogage d'Android plutôt que d'affaiblir la logique de validation des versions de production.

Comment les applications Android doivent-elles gérer l'inspection TLS en entreprise ?

Les équipes doivent décider explicitement de cette politique avant le déploiement. Comme le pinning valide des éléments de clé précis, les environnements qui inspectent TLS peuvent échouer par conception : le comportement attendu doit donc être documenté plutôt que découvert par les utilisateurs pendant le déploiement.

Quel est le point de départ le plus moderne pour les nouvelles applications Android ?

Pour la plupart des nouvelles applications, commencez par Network Security Configuration pour un pinning déclaratif centralisé, ou utilisez OkHttp CertificatePinner lorsque la couche réseau est déjà centrée sur OkHttp. Ne conservez les configurations TLS personnalisées propres à d'anciennes bibliothèques que pour la maintenance de code hérité