La plupart des développeurs d'applications intégreront des bibliothèques tierces à leurs applications. Si c'est pour accéder à un service, tel que Dropbox ou YouTube, ou pour consigner les plantages. Le nombre de bibliothèques et de services tiers est stupéfiant. La plupart de ces bibliothèques et services sont intégrés en s'authentifiant d'une manière ou d'une autre avec le service, la plupart du temps, cela se fait via une clé API. Pour des raisons de sécurité, les services génèrent généralement une clé publique et privée, souvent également appelée clé secrète. Malheureusement, pour se connecter aux services, cette clé privée doit être utilisée pour s'authentifier et, par conséquent, faire probablement partie de l'application. Inutile de dire que cela fait face à un immense problème de sécurité. Les clés API publiques et privées peuvent être extraites des fichiers APK en quelques minutes et peuvent facilement être automatisées.
En supposant que j'ai quelque chose de similaire à cela, comment puis-je protéger la clé secrète:
public class DropboxService {
private final static String APP_KEY = "jk433g34hg3";
private final static String APP_SECRET = "987dwdqwdqw90";
private final static AccessType ACCESS_TYPE = AccessType.DROPBOX;
// SOME MORE CODE HERE
}
Quelle est, selon vous, la manière la meilleure et la plus sûre de stocker la clé privée? Obfuscation, cryptage, qu'en pensez-vous?
la source
Réponses:
En l'état, votre application compilée contient les chaînes de clés, mais aussi les noms constants APP_KEY et APP_SECRET. Extraire des clés d'un tel code auto-documenté est trivial, par exemple avec l'outil Android standard dx.
Vous pouvez appliquer ProGuard. Il laissera les chaînes de touches intactes, mais il supprimera les noms constants. Il renommera également les classes et les méthodes avec des noms courts et dénués de sens, dans la mesure du possible. Extraire les clés prend alors un peu plus de temps, pour déterminer quelle chaîne sert à quelle fin.
Notez que la configuration de ProGuard ne devrait pas être aussi difficile que vous le craignez. Pour commencer, il vous suffit d'activer ProGuard, comme indiqué dans project.properties. En cas de problème avec les bibliothèques tierces, vous devrez peut-être supprimer certains avertissements et / ou empêcher leur obscurcissement, dans proguard-project.txt. Par exemple:
Il s'agit d'une approche par force brute; vous pouvez affiner une telle configuration une fois que l'application traitée fonctionne.
Vous pouvez brouiller les chaînes manuellement dans votre code, par exemple avec un encodage Base64 ou de préférence avec quelque chose de plus compliqué; peut-être même du code natif. Un pirate devra alors effectuer une rétro-ingénierie statique de votre encodage ou intercepter dynamiquement le décodage au bon endroit.
Vous pouvez appliquer un obfuscateur commercial, comme le frère spécialisé de ProGuard ProGuard, DexGuard . Il peut également chiffrer / masquer les chaînes et les classes pour vous. Extraire les clés prend alors encore plus de temps et d'expertise.
Vous pourrez peut-être exécuter des parties de votre application sur votre propre serveur. Si vous pouvez y garder les clés, elles sont en sécurité.
En fin de compte, c'est un compromis économique que vous devez faire: quelle est l'importance des clés, combien de temps ou de logiciels pouvez-vous vous permettre, à quel point les pirates informatiques sont intéressés par les clés, combien de temps voudront-ils dépenser, combien vaut un délai avant que les clés ne soient piratées, à quelle échelle les pirates réussis distribueront-ils les clés, etc. De petites informations comme les clés sont plus difficiles à protéger que des applications entières. Intrinsèquement, rien du côté client n'est incassable, mais vous pouvez certainement relever la barre.
(Je suis le développeur de ProGuard et DexGuard)
la source
Peu d'idées, à mon avis seule la première donne une garantie:
Gardez vos secrets sur un serveur sur Internet et, si nécessaire, saisissez-les et utilisez-les. Si l'utilisateur est sur le point d'utiliser Dropbox, rien ne vous empêche de faire une demande à votre site et d'obtenir votre clé secrète.
Mettez vos secrets en code jni, ajoutez du code variable pour rendre vos bibliothèques plus grandes et plus difficiles à décompiler. Vous pouvez également diviser la chaîne de clés en quelques parties et les conserver à divers endroits.
utilisez l'obfuscateur, mettez également du code haché secret et, plus tard, décochez-le lorsque vous en avez besoin.
Mettez votre clé secrète en tant que derniers pixels de l'une de vos images dans les ressources. Ensuite, au besoin, lisez-le dans votre code. L'obscurcissement de votre code devrait aider à masquer le code qui le lira.
Si vous voulez voir rapidement à quel point il est facile de lire votre code apk, saisissez APKAnalyser:
http://developer.sonymobile.com/knowledge-base/tool-guides/analyse-your-apks-with-apkanalyser/
la source
Une autre approche consiste à ne pas avoir le secret sur l'appareil en premier lieu! Voir Techniques de sécurité des API mobiles (en particulier la partie 3).
En utilisant la tradition séculaire de l'indirection, partagez le secret entre votre point de terminaison API et un service d'authentification d'application.
Lorsque votre client souhaite effectuer un appel API , il demande au service d'authentification de l'application de l'authentifier (à l'aide de techniques d'attestation à distance puissantes) et il reçoit un jeton limité dans le temps (généralement JWT ) signé par le secret.
Le jeton est envoyé avec chaque appel d'API où le point de terminaison peut vérifier sa signature avant d'agir sur la demande.
Le secret réel n'est jamais présent sur l'appareil; en fait, l'application n'a aucune idée si elle est valide ou non, elle jute les demandes d'authentification et transmet le jeton résultant. Comme avantage de l'indirection, si vous souhaitez changer le secret, vous pouvez le faire sans que les utilisateurs mettent à jour leurs applications installées.
Donc, si vous souhaitez protéger votre secret, ne pas l'avoir dans votre application en premier lieu est une très bonne façon de procéder.
la source
Ancienne voie non sécurisée:
Suivez 3 étapes simples pour sécuriser l'API / la clé secrète ( ancienne réponse )
Nous pouvons utiliser Gradle pour sécuriser la clé API ou la clé secrète.
1. gradle.properties (Propriétés du projet): créer une variable avec la clé.
2. build.gradle (Module: app): Définissez la variable dans build.gradle pour y accéder en activité ou en fragment. Ajoutez le code ci-dessous aux buildTypes {}.
3. Accédez-y dans Activity / Fragment par l'application BuildConfig:
Mise à jour :
La solution ci-dessus est utile dans le projet open source pour valider via Git. (Merci à David Rawson et riyaz-ali pour votre commentaire).
Selon les commentaires de Matthew et Pablo Cegarra, la méthode ci-dessus n'est pas sécurisée et Decompiler permettra à quelqu'un d'afficher le BuildConfig avec nos clés secrètes.
Solution :
Nous pouvons utiliser NDK pour sécuriser les clés API. Nous pouvons stocker des clés dans la classe C / C ++ native et y accéder dans nos classes Java.
Veuillez suivre ce blog pour sécuriser les clés d'API à l'aide de NDK.
Un suivi sur la façon de stocker des jetons en toute sécurité dans Android
la source
gradle.properties
ne doit pas être enregistré dans Git, c'est donc un moyen de garder le secret hors du code source engagé, au moinsapk
(il sera ajouté auBuildConfig
fichier généré ), bien que ce soit certainement une bonne idée de gérer différentes clés API (par exemple dans un projet open source)BuildConfig.java
fichier aura la clé sous forme de texte brut. Ce n'est pas mieux que ce que le PO fait déjà.pour ces gars-là, il ne se cachera pas, verrouillez
ProGuard
le code. Il s'agit d'un refactoriseur et certains obscurcisseurs payants insèrent quelques opérateurs au niveau du bit pour récupérer lejk433g34hg3
chaîne. Vous pouvez augmenter de 5 à 15 minutes le piratage si vous travaillez 3 jours :)Le meilleur moyen est de le garder tel quel, à mon humble avis.
Même si vous stockez côté serveur (votre PC), la clé peut être piratée et imprimée. Peut-être que cela prend le plus de temps? Quoi qu'il en soit, il s'agit de quelques minutes ou de quelques heures dans le meilleur des cas.
Un utilisateur normal ne décompilera pas votre code.
la source
Une solution possible consiste à coder les données dans votre application et à utiliser le décodage lors de l'exécution (lorsque vous souhaitez utiliser ces données). Je recommande également d'utiliser progaurd pour rendre difficile la lecture et la compréhension du code source décompilé de votre application. par exemple, j'ai mis une clé codée dans l'application, puis j'ai utilisé une méthode de décodage dans mon application pour décoder mes clés secrètes au moment de l'exécution:
Le code source décompilé d'une application proguarded est le suivant:
Au moins, c'est assez compliqué pour moi. c'est la façon dont je fais quand je n'ai pas d'autre choix que de stocker une valeur dans mon application. Bien sûr, nous savons tous que ce n'est pas la meilleure façon, mais cela fonctionne pour moi.
Version décompilée:
et vous pouvez trouver autant de classes de chiffrement avec une petite recherche dans google.
la source
En ajoutant à la solution @Manohar Reddy, la base de données Firebase ou Firebase RemoteConfig (avec une valeur par défaut Null) peut être utilisé:
Qu'est-ce qui est différent dans cette solution?
la source
Cet exemple a plusieurs aspects différents. Je mentionnerai quelques points qui, je pense, n'ont pas été explicitement abordés ailleurs.
Protéger le secret en transit
La première chose à noter est que l'accès à l'API Dropbox à l'aide de leur mécanisme d' authentification d'application vous oblige à transmettre votre clé et votre secret. La connexion est HTTPS, ce qui signifie que vous ne pouvez pas intercepter le trafic sans connaître le certificat TLS. Il s'agit d'empêcher une personne d'intercepter et de lire les paquets pendant son trajet de l'appareil mobile vers le serveur. Pour les utilisateurs normaux, c'est un très bon moyen de garantir la confidentialité de leur trafic.
Ce qui n'est pas bon, c'est d'empêcher une personne malveillante de télécharger l'application et d'inspecter le trafic. Il est vraiment facile d'utiliser un proxy man-in-the-middle pour tout le trafic entrant et sortant d'un appareil mobile. Il ne nécessiterait aucun démontage ni ingénierie inverse du code pour extraire la clé et le secret de l'application dans ce cas en raison de la nature de l'API Dropbox.
Vous pouvez effectuer un épinglage qui vérifie que le certificat TLS que vous recevez du serveur est celui que vous attendez. Cela ajoute une vérification au client et rend plus difficile l'interception du trafic. Cela rendrait plus difficile l'inspection du trafic en vol, mais la vérification de l'épinglage se produit chez le client, il serait donc toujours possible de désactiver le test d'épinglage. Cela rend cependant les choses plus difficiles.
Protéger le secret au repos
Dans un premier temps, l'utilisation de quelque chose comme proguard aidera à rendre moins évident où se trouvent les secrets. Vous pouvez également utiliser le NDK pour stocker la clé et le secret et envoyer des demandes directement, ce qui réduirait considérablement le nombre de personnes possédant les compétences appropriées pour extraire les informations. Un obscurcissement supplémentaire peut être obtenu en ne stockant pas les valeurs directement en mémoire pendant une durée quelconque, vous pouvez les crypter et les décrypter juste avant l'utilisation comme suggéré par une autre réponse.
Options plus avancées
Si vous êtes maintenant paranoïaque à l'idée de mettre le secret n'importe où dans votre application et que vous avez le temps et l'argent pour investir dans des solutions plus complètes, vous pouvez envisager de stocker les informations d'identification sur vos serveurs (en supposant que vous en ayez). Cela augmenterait la latence de tous les appels à l'API, car elle devra communiquer via votre serveur, et pourrait augmenter les coûts de fonctionnement de votre service en raison de l'augmentation du débit de données.
Vous devez ensuite décider de la meilleure façon de communiquer avec vos serveurs pour vous assurer qu'ils sont protégés. Ceci est important pour éviter que les mêmes problèmes ne se reproduisent avec votre API interne. La meilleure règle empirique que je puisse donner est de ne transmettre aucun secret directement à cause de la menace de l'homme du milieu. Au lieu de cela, vous pouvez signer le trafic à l'aide de votre secret et vérifier l'intégrité de toutes les demandes envoyées à votre serveur. Une façon standard de procéder consiste à calculer un HMAC du message saisi sur un secret. Je travaille dans une entreprise qui a un produit de sécurité qui opère également dans ce domaine, c'est pourquoi ce genre de choses m'intéresse. En fait, voici un article de blog de l'un de mes collègues qui revient sur la plupart de cela.
Combien dois-je faire?
Avec des conseils de sécurité comme celui-ci, vous devez prendre une décision en termes de coûts / avantages sur la difficulté à faire en sorte que quelqu'un pénètre. Si vous êtes une banque protégeant des millions de clients, votre budget est totalement différent de celui qui prend en charge une application dans leur temps libre. Il est pratiquement impossible d'empêcher quelqu'un de briser votre sécurité, mais dans la pratique, peu de gens ont besoin de toutes les cloches et sifflets et avec quelques précautions de base, vous pouvez faire du chemin.
la source
La solution la plus sécurisée consiste à conserver vos clés sur un serveur et à acheminer toutes les demandes nécessitant cette clé via votre serveur. De cette façon, la clé ne quitte jamais votre serveur, aussi longtemps que votre serveur est sécurisé, votre clé l'est également. Bien sûr, il y a un coût de performance avec cette solution.
la source
Gardez le secret
firebase database
et obtenez-en lorsque l'application démarre, c'est bien mieux que d'appeler un service Web.la source
Quoi que vous fassiez pour sécuriser vos clés secrètes ne sera pas une vraie solution. Si le développeur peut décompiler l'application, il n'y a aucun moyen de sécuriser la clé, masquer la clé n'est qu'une sécurité par obscurité, tout comme l'obscurcissement du code. Le problème avec la sécurisation d'une clé secrète est que pour la sécuriser, vous devez utiliser une autre clé et cette clé doit également être sécurisée. Pensez à une clé cachée dans une boîte verrouillée avec une clé. Vous placez une boîte à l'intérieur d'une pièce et verrouillez la pièce. Il vous reste une autre clé à sécuriser. Et cette clé sera toujours codée en dur dans votre application.
Donc, à moins que l'utilisateur n'entre un code PIN ou une phrase, il n'y a aucun moyen de masquer la clé. Mais pour ce faire, vous devez avoir un schéma de gestion des codes PIN se produisant hors bande, c'est-à-dire via un canal différent. Certainement pas pratique pour sécuriser les clés de services comme les API Google.
la source
Âge ancien poste, mais toujours assez bon. Je pense que le cacher dans une bibliothèque .so serait génial, en utilisant NDK et C ++ bien sûr. Les fichiers .so peuvent être visualisés dans un éditeur hexadécimal, mais bonne chance pour décompiler cela: P
la source
La seule véritable façon de garder ces informations privées est de les conserver sur votre serveur et de demander à l'application d'envoyer quoi que ce soit au serveur, et le serveur interagit avec Dropbox. De cette façon, vous ne distribuez JAMAIS votre clé privée dans n'importe quel format.
la source
Sur la base d'une expérience amère, et après avoir consulté un expert IDA-Pro, la meilleure solution consiste à déplacer une partie clé du code dans une DLL / SharedObject, puis à la récupérer à partir d'un serveur et à la charger lors de l'exécution.
Les données sensibles doivent être encodées car il est très facile de faire quelque chose comme ceci:
la source