42 votes

Comment protéger la clé publique de Google Play lors de la facturation InApp

En fait, c'est un peu ridicule de protéger la clé publique (quelle est alors la définition de la clé publique?) mais selon la documentation de Google:

Pour protéger votre clé publique des utilisateurs malveillants et des hackers, ne l'intégrez pas dans un code en tant que chaîne littérale. Au lieu de cela, construisez la chaîne au moment de l'exécution à partir de morceaux ou utilisez la manipulation de bits (par exemple, XOR avec une autre chaîne) pour masquer la clé réelle. La clé elle-même n'est pas une information secrète, mais vous ne voulez pas faciliter la tâche à un pirate ou à un utilisateur malveillant de remplacer la clé publique par une autre clé.

Y a-t-il une manière recommandée de le faire?

Je sais qu'il y a plusieurs façons de le faire, je ne veux simplement pas suivre la même méthode que celle utilisée pour le hachage de mot de passe dans le passé (par exemple, md5, sha1, etc), je veux connaître la meilleure pratique dans le cas d'utilisation ci-dessus.

38voto

Nikolay Elenkov Points 32843

Ceci revient souvent par ici :) L'idée derrière le paragraphe que vous citez est que pour que la facturation in-app soit sécurisée, vous devez vérifier les signatures de transaction. Celles-ci sont signées avec une clé privée, associée à votre compte développeur. La clé réside sur les serveurs de Google, donc on peut raisonnablement supposer que personne d'autre ne peut signer des données avec. Pour la vérifier, vous avez besoin de votre clé publique, que vous pouvez copier depuis la console développeur. Si quelqu'un la remplaçait dans votre application, il pourrait la tromper pour accepter des transactions de facturation in-app provenant de sources non autorisées, car s'ils plantent la clé publique, ils contrôlent probablement également la clé privée correspondante. En pratique cependant, il est beaucoup plus simple de simplement modifier votre code aux bons endroits pour toujours renvoyer true pour isLicensed(), hasItem() ou des méthodes similaires que vous pourriez avoir et personne ne fait cela.

La meilleure façon de protéger la clé est bien sûr de ne pas avoir la clé du tout dans votre application. Déplacez toute la logique de validation de transaction vers votre serveur, et utilisez HTTPS pour vous y connecter. Validez correctement la chaîne de certificats pour vous assurer que vous communiquez avec vos propres serveurs. Sinon, quelqu'un pourrait jouer avec le DNS et tromper votre application pour se connecter à leurs propres serveurs. Une attaque similaire contre les achats iOS a été annoncée il y a quelques semaines.

La deuxième meilleure chose est d'obfusquer d'une manière ou d'une autre la clé, et de l'inclure dans votre application. Cela a l'avantage de ne pas avoir besoin d'un serveur, mais l'inconvénient est que si quelqu'un est suffisamment déterminé, il finira par le découvrir, car il peut toujours inverser le code binaire de votre application. Votre meilleure solution est donc de trouver votre propre manière originale de le faire qui ne soit pas publiée sur les forums publics :) Pour rendre les choses un peu plus difficiles, vous pouvez implémenter la partie de validation en code natif, ce qui est plus difficile (mais pas impossible) à analyser. Cependant, comme mentionné ci-dessus, patcher le code binaire aux bons endroits est bien plus simple que d'essayer de remplacer la clé publique, c'est donc ce que la plupart des crackers feront.

32voto

Pointer Null Points 14229

Faites au moins une transformation de texte simple. L'idée est que le simple désassemblage ne révélera pas votre clé publique.

Voici un exemple de fonction qui effectue un encodage/décodage de chaîne simple :

/**
 * Transformation simple de chaîne en faisant un XOR sur tous les caractères par une valeur.
 */
static String stringTransform(String s, int i) {
   char[] chars = s.toCharArray();
   for(int j = 0; j

`

Ensuite, votre clé privée est stockée dans le code source sous forme de chaîne encodée (encodez-la avec cette fonction), et décodée au moment de l'exécution avec la même fonction. C'est un genre de méthode "XOR" suggérée par Google.

Vous choisissez vous-même le paramètre 'i', n'importe quoi de aléatoire comme 0x27 ou autre fonctionnera. Si vous cachez plus de chaînes de cette manière, utilisez un 'i' différent pour chaque transformation.

`

11voto

Eric Lafortune Points 17656

Comme alternative à l'obfuscation manuelle de la clé, vous pouvez également laisser un obfuscateur le faire automatiquement. ProGuard fait partie du SDK Android, mais il obfusque principalement les noms de classes/champs/méthodes, pas les chaînes. Son cousin spécialisé pour Android, DexGuard, peut ajouter plusieurs couches d'obfuscation, en appliquant un chiffrement des chaînes, un chiffrement des classes et des réflexions. Ce n'est pas gratuit, mais cela fait gagner du temps et c'est probablement plus efficace que de le faire manuellement.

(Je suis le développeur de ProGuard et DexGuard)

4voto

skygeek Points 940

Enregistrez votre clé publique du côté serveur et une fois que vous recevez une réponse de Google Play pour vérifier la clé, envoyez cette réponse au serveur et effectuez votre opération là-bas sur le serveur.

1voto

darrenp Points 872

La clé publique est codée en base64 ([a-zA-Z0-9+/]) donc vous pouvez facilement éviter le besoin d'échapper la chaîne obfusquée car c'est un problème ennuyeux dans la solution de @PointerNull.

À la place, vous pouvez effectuer l'obfuscation en convertissant d'abord le caractère en question en un entier sur 6 bits. Ensuite, effectuez la manipulation des bits (par exemple le XOR) et ensuite reconvertissez en un caractère encodé en base64. Aucun échappement de caractère nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X