SSL Pinning
Certificate pinning pour les appels API — quand c'est nécessaire et comment le configurer dans React Native.
SSL Pinning
Le certificate pinning (SSL pinning) garantit que votre app communique uniquement avec votre serveur spécifique en vérifiant le certificat du serveur contre une copie connue, empêchant les attaques man-in-the-middle même sur des réseaux compromis.
Quand en avez-vous besoin
| Scénario | SSL Pinning ? |
|---|---|
| App SaaS standard | Généralement pas nécessaire |
| App bancaire / financière | Requis |
| Santé / données médicales | Requis |
| App traitant des données gouvernementales | Requis |
| Entreprise avec exigences de conformité | Probablement nécessaire |
Pour la plupart des apps, HTTPS avec une validation de certificat appropriée est suffisant. Le SSL pinning ajoute de la complexité et un surcoût de maintenance (vous devez mettre à jour l'app quand les certificats changent).
Comment ça marche
Sans pinning :
- L'app se connecte au serveur
- L'OS vérifie le certificat du serveur contre toute CA de confiance
- Connexion établie
Avec pinning :
- L'app se connecte au serveur
- L'app vérifie le certificat du serveur contre un certificat ou clé publique spécifique
- Si ça ne correspond pas, la connexion est rejetée
Cela empêche les attaques où une CA malveillante émet un faux certificat pour votre domaine.
Implémentation avec expo-network
Pour un pinning basique dans Expo, utilisez un wrapper fetch personnalisé :
import { Platform } from "react-native";
const PINNED_CERTIFICATES = {
"api.example.com": "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
};
// Note : Le vrai certificate pinning nécessite des modules natifs
// Cet exemple montre le concept — utilisez une bibliothèque en productionBibliothèque React Native SSL Pinning
Pour les apps en production, utilisez react-native-ssl-pinning :
npm install react-native-ssl-pinning
npx expo prebuildimport { fetch as pinnedFetch } from "react-native-ssl-pinning";
async function secureApiCall(endpoint: string) {
const response = await pinnedFetch(`https://api.example.com${endpoint}`, {
method: "GET",
headers: { "Content-Type": "application/json" },
sslPinning: {
certs: ["my-server-cert"], // Nom du fichier de certificat sans extension
},
});
return await response.json();
}Ajouter les certificats
- Exportez le certificat depuis votre serveur :
openssl s_client -connect api.example.com:443 -showcerts < /dev/null \
| openssl x509 -outform DER -out my-server-cert.cer- Placez le fichier de certificat :
- iOS : Ajoutez
my-server-cert.cerau projet Xcode - Android : Placez dans
android/app/src/main/assets/
Pinning de clé publique
Pinnez la clé publique au lieu du certificat complet. Cela survit aux renouvellements de certificat tant que la paire de clés reste la même :
const response = await pinnedFetch("https://api.example.com/data", {
method: "GET",
sslPinning: {
certs: ["my-server-cert"],
},
pkPinning: true, // Pinner la clé publique, pas le certificat complet
});Stratégie de rotation des certificats
Les certificats expirent. Planifiez la rotation :
- Pinnez plusieurs certificats — Incluez le certificat actuel et le prochain
- Utilisez le pinning de clé publique — Les clés peuvent rester les mêmes entre les renouvellements
- Bypass d'urgence — Envisagez un flag de config distante pour désactiver le pinning si nécessaire
- Surveillez l'expiration — Alertez avant que les certificats n'expirent
// Pinner les certificats actuel et de secours
const response = await pinnedFetch(url, {
sslPinning: {
certs: ["current-cert", "backup-cert"],
},
});Considérations importantes
- Le SSL pinning nécessite un build de développement (pas Expo Go)
- Vous devez mettre à jour l'app quand les certificats changent (sauf avec le pinning de clé publique)
- Le pinning peut casser pendant le développement si vous utilisez des outils proxy (Charles, Proxyman)
- Ajoutez un mode debug qui désactive le pinning en
__DEV__:
const fetchOptions = __DEV__
? { method: "GET" }
: { method: "GET", sslPinning: { certs: ["my-cert"] } };Tests
| Outil | Objectif |
|---|---|
| Charles Proxy | Vérifier que le pinning bloque le trafic intercepté |
| mitmproxy | Tester la détection man-in-the-middle |
openssl s_client | Inspecter les certificats serveur |
Pour vérifier que le pinning fonctionne :
- Activez Charles Proxy ou mitmproxy
- Faites un appel API depuis votre app
- L'appel devrait échouer avec une erreur de certificat — cela signifie que le pinning fonctionne