Stocker des données en toute sécurité sur Android 1

Stocker des données en toute sécurité sur Android

La crédibilité d’une application dépend aujourd’hui fortement de la manière dont les données privées de l’utilisateur sont gérées. La pile Android dispose de nombreuses API puissantes entourant le stockage des informations d’identification et des clés, avec des fonctionnalités spécifiques disponibles uniquement dans certaines versions.

Cette courte série débutera par une approche simple pour être opérationnel en examinant le système de stockage et comment crypter et stocker des données sensibles via un code d’accès fourni par l’utilisateur. Dans le deuxième didacticiel, nous examinerons des moyens plus complexes de protéger les clés et les informations d’identification.

Les bases

La première question à se poser est de savoir combien de données vous devez réellement acquérir. Une bonne approche consiste à éviter de stocker des données privées si vous n’en avez pas vraiment besoin.

Pour les données que vous devez stocker, l’architecture Android est prête à vous aider. Depuis la version 6.0 Marshmallow, le chiffrement complet du disque est activé par défaut, pour les périphériques dotés de la capacité. Fichiers et
SharedPreferences qui sont enregistrés par l’application sont automatiquement définis avec le MODE_PRIVATE constant. Cela signifie que les données ne sont accessibles que par votre propre application.

C’est une bonne idée de s’en tenir à cette valeur par défaut. Vous pouvez le définir explicitement lors de l’enregistrement d’une préférence partagée.

Ou lors de l’enregistrement d’un fichier.

Évitez de stocker des données sur un stockage externe, car les données sont alors visibles par d’autres applications et utilisateurs. En fait, pour rendre plus difficile la copie du binaire et des données de votre application, vous pouvez empêcher les utilisateurs de pouvoir installer l’application sur un stockage externe. Ajouter android:installLocation
avec une valeur de internalOnly dans le fichier manifeste accomplira cela.

Vous pouvez également empêcher l’application et ses données d’être sauvegardées. Cela empêche également le téléchargement du contenu du répertoire de données privé d’une application à l’aide de adb backup. Pour ce faire, définissez le android:allowBackup attribuer à false dans le fichier manifeste. Par défaut, cet attribut est défini sur true.

Ce sont des bonnes pratiques, mais elles ne fonctionneront pas pour un appareil compromis ou enraciné, et le chiffrement du disque n’est utile que lorsque l’appareil est sécurisé avec un écran de verrouillage. C’est là que le fait d’avoir un mot de passe côté application qui protège ses données avec un cryptage est bénéfique.

Sécurisation des données utilisateur avec un mot de passe

Cacher est un excellent choix pour une bibliothèque de chiffrement, car il vous permet d’être opérationnel très rapidement sans avoir à vous soucier des détails sous-jacents. Cependant, un exploit ciblé pour un framework populaire affectera simultanément toutes les applications qui en dépendent.

Il est également important de connaître le fonctionnement des systèmes de cryptage afin de pouvoir savoir si vous utilisez un framework particulier en toute sécurité. Donc, pour cet article, nous allons nous salir les mains en regardant directement le fournisseur de cryptographie.

AES et dérivation de clé basée sur un mot de passe

Nous utiliserons le recommandé AES standard, qui crypte les données à partir d’une clé. La même clé utilisée pour crypter les données est utilisée pour décrypter les données, ce que l’on appelle le cryptage symétrique. Il existe différentes tailles de clé et AES256 (256 bits) est la longueur préférée pour une utilisation avec des données sensibles.

Bien que l’expérience utilisateur de votre application doive forcer un utilisateur à utiliser un code d’accès fort, il est possible que le même code d’accès soit également choisi par un autre utilisateur. Mettre la sécurité de nos données cryptées entre les mains de l’utilisateur n’est pas sûr. Nos données doivent plutôt être sécurisées avec un
clé qui est aléatoire et suffisamment grand (c’est-à-dire qui a suffisamment d’entropie) pour être considéré comme fort. C’est pourquoi il n’est jamais recommandé d’utiliser un mot de passe directement pour crypter les données. C’est là qu’une fonction appelée Fonction de dérivation de clé basée sur un mot de passe (PBKDF2) entre en jeu.

PBKDF2 dérive un clé de mot de passe par hachage
plusieurs fois avec un sel. C’est ce qu’on appelle l’étirement des touches. Le sel n’est qu’une séquence aléatoire de données et rend la clé dérivée unique même si le même mot de passe a été utilisé par quelqu’un d’autre.

Commençons par générer ce sel.

le SecureRandom class garantit que la sortie générée sera difficile à prédire – c’est un « générateur de nombres aléatoires cryptographiquement fort ». Nous pouvons maintenant mettre le sel et le mot de passe dans un objet de chiffrement basé sur un mot de passe: PBEKeySpec. Le constructeur de l’objet prend également une forme de nombre d’itérations, ce qui rend la clé plus forte. En effet, l’augmentation du nombre d’itérations augmente le temps nécessaire pour opérer sur un ensemble de clés lors d’une attaque par force brute. le PBEKeySpec
puis passe dans le SecretKeyFactory, qui génère finalement la clé sous forme de
byte[] tableau. Nous allons envelopper cela brut byte[] tableau en un SecretKeySpec objet.

Notez que le mot de passe est passé comme un char[] array et le PBEKeySpec
classe le stocke comme un char[] tableau aussi. char[] les tableaux sont généralement utilisés pour les fonctions de chiffrement car, String la classe est immuable, un char[] Le tableau contenant des informations sensibles peut être écrasé, supprimant ainsi entièrement les données sensibles de la mémoire de l’appareil.

Vecteurs d’initialisation

Nous sommes maintenant prêts à crypter les données, mais nous avons encore une chose à faire. Il existe différents modes de cryptage avec AES, mais nous utiliserons celui recommandé: le chaînage de blocs de chiffrement (CBC). Cela fonctionne sur nos données un bloc à la fois. L’avantage de ce mode est que chaque bloc de données non crypté suivant est XOR‘d avec le bloc crypté précédent pour rendre le cryptage plus fort. Cependant, cela signifie que le premier bloc n’est jamais aussi unique que tous les autres!

Si un message à chiffrer devait commencer de la même manière qu’un autre message à chiffrer, la sortie chiffrée de début serait la même, ce qui donnerait à un attaquant un indice pour déterminer ce que le message pourrait être. La solution est d’utiliser un vecteur d’initialisation (IV).

Un IV est juste un bloc d’octets aléatoires qui sera XOR avec le premier bloc de données utilisateur. Étant donné que chaque bloc dépend de tous les blocs traités jusqu’à ce point, le message entier sera chiffré de manière unique – des messages identiques chiffrés avec la même clé ne produiront pas des résultats identiques.

Créons maintenant un IV.

Une note sur SecureRandom. Sur les versions 4.3 et antérieures, l’architecture de cryptographie Java présentait une vulnérabilité due à une initialisation incorrecte du générateur de nombres pseudo-aléatoires sous-jacent (PRNG). Si vous ciblez les versions 4.3 et inférieures, un correctif est disponible.

Crypter les données

Armé d’un
IvParameterSpec, nous pouvons maintenant faire le cryptage proprement dit.

Ici on passe dans la ficelle "AES/CBC/PKCS7Padding". Cela spécifie le cryptage AES avec chaînage de blocs de chiffrement. La dernière partie de cette chaîne fait référence à PKCS7, qui est une norme établie pour les données de remplissage qui ne correspondent pas parfaitement à la taille du bloc. (Les blocs sont de 128 bits et le remplissage est effectué avant le cryptage.)

Pour compléter notre exemple, nous allons mettre ce code dans une méthode de chiffrement qui regroupera le résultat dans un HashMap
contenant les données cryptées, ainsi que le sel et le vecteur d’initialisation nécessaires au décryptage.

La méthode de décryptage

Il vous suffit de stocker l’IV et le sel avec vos données. Bien que les sels et les intraveineuses soient considérés comme publics, assurez-vous qu’ils ne sont pas incrémentés ou réutilisés séquentiellement. Pour décrypter les données, il suffit de changer le mode dans le Cipher constructeur de
ENCRYPT_MODE à DECRYPT_MODE.

La méthode de déchiffrement prendra un HashMap
qui contient les mêmes informations requises (données cryptées, sel et IV) et renvoie un fichier décrypté byte[] array, avec le mot de passe correct. La méthode de déchiffrement régénérera la clé de chiffrement à partir du mot de passe. La clé ne doit jamais être stockée!

Test du cryptage et du décryptage

Pour garder l’exemple simple, nous omettons la vérification des erreurs qui garantirait que le HashMap contient la clé requise, les paires de valeurs. Nous pouvons maintenant tester nos méthodes pour nous assurer que les données sont correctement décryptées après le cryptage.

Les méthodes utilisent un byte[] tableau afin que vous puissiez crypter des données arbitraires au lieu de seulement String objets.

Sauvegarde des données chiffrées

Maintenant que nous avons un crypté byte[]
tableau, nous pouvons l’enregistrer dans le stockage.

Si vous ne vouliez pas enregistrer l’IV et le sel séparément, HashMap est sérialisable avec le ObjectInputStream et ObjectOutputStream Des classes.

Sauvegarde des données sécurisées sur SharedPreferences

Vous pouvez également enregistrer des données sécurisées dans votre application SharedPreferences.

Depuis le SharedPreferences est un système XML qui n’accepte que des primitives et des objets spécifiques comme valeurs, nous devons convertir nos données dans un format compatible tel qu’un String objet. Base64
nous permet de convertir les données brutes en un String représentation qui ne contient que les caractères autorisés par le Format XML. Chiffrez à la fois la clé et la valeur afin qu’un attaquant ne puisse pas comprendre à quoi pourrait servir une valeur.

Dans l’exemple ci-dessus, encryptedKey et encryptedValue sont tous deux cryptés byte[] tableaux renvoyés par notre encryptBytes() méthode. Le IV et le sel peuvent être enregistrés dans le fichier de préférences ou dans un fichier séparé. Pour récupérer les octets chiffrés du SharedPreferences, nous pouvons appliquer un décodage Base64 sur le String.

Effacement des données non sécurisées des anciennes versions

Maintenant que les données stockées sont sécurisées, il se peut que vous disposiez d’une version précédente de l’application dans laquelle les données étaient stockées de manière non sécurisée. Lors d’une mise à niveau, les données peuvent être effacées et rechiffrées. Le code suivant efface un fichier à l’aide de données aléatoires.

En théorie, vous pouvez simplement supprimer vos préférences partagées en supprimant le /data/data/com.your.package.name/shared_prefs/your_prefs_name.xml et your_prefs_name.bak fichiers et effacer les préférences en mémoire avec le code suivant:

Cependant, au lieu d’essayer d’effacer les anciennes données et d’espérer que cela fonctionne, il est préférable de les crypter en premier lieu! Cela est particulièrement vrai en général pour les disques SSD qui répartissent souvent les écritures de données dans différentes régions pour éviter l’usure. Cela signifie que même si vous écrasez un fichier dans le système de fichiers, la mémoire physique à semi-conducteurs peut conserver vos données dans leur emplacement d’origine sur le disque.

Conclusion

Cela conclut notre tutoriel sur le stockage de données cryptées. Dans cet article, vous avez appris à crypter et décrypter en toute sécurité des données sensibles avec un mot de passe fourni par l’utilisateur. C’est facile à faire quand vous savez comment faire, mais il est important de suivre toutes les meilleures pratiques pour vous assurer que les données de vos utilisateurs sont vraiment sécurisées.

Dans le prochain article, nous verrons comment tirer parti du KeyStore et d’autres API liées aux informations d’identification pour stocker des éléments en toute sécurité. En attendant, consultez certains de nos autres articles intéressants sur le développement d’applications Android.

Soutenez notre effort ❤️

Si vous avez apprécié cet article, pensez à laisser un pourboire pour nous aider à continuer à publier du contenu de qualité.

Paiement sécurisé sur PayPal
Moyens I/O Staff est une équipe de rédacteurs spécialisés, passionnés par la technologie, l’innovation et les usages numériques. Forts d’une expertise pointue en IA, applications mobiles, gaming et tendances digitales, nous produisons un contenu rigoureux, vérifié et utile. Notre mission : vous offrir une information fiable et claire pour mieux naviguer dans le monde numérique en constante évolution. Découvrez les avis de nos lecteurs sur Trustpilot.