Les développeurs utilisent la cryptographie pour protéger la confidentialité et l'intégrité des données à l'aide de puissants algorithmes. Cependant, le stockage des clés est souvent sous-utilisé, et il est courant qu'elles soient codées en dur dans l'application sous la forme d'un tableau d'octets ou de chaînes dans le code ou dans un fichier d'éléments tel que strings.xml. Si des secrets sont exposés dans des fichiers de l'application, cela va à l'encontre du principe de Kerchoff, et le modèle de sécurité peut être considéré comme compromis.
Impact
Un pirate ayant accès à des outils de rétro-ingénierie peut récupérer très facilement un secret codé en dur. L'impact peut varier en fonction des conditions, mais dans de nombreux cas, cela peut entraîner des problèmes de sécurité majeurs, tels que l'accès à des données sensibles.
Stratégies d'atténuation
Pour atténuer ce problème, pensez à utiliser l'API KeyChain lorsque vous souhaitez obtenir des identifiants à l'échelle du système, ou le fournisseur Android Keystore pour permettre à une application de stocker ses propres identifiants auxquels elle seule peut accéder.
L'extrait de code suivant montre comment stocker et utiliser une clé symétrique à l'aide de KeyStore :
Kotlin
privatevalANDROID_KEY_STORE_PROVIDER="AndroidKeyStore"privatevalANDROID_KEY_STORE_ALIAS="AES_KEY_DEMO"@Throws(KeyStoreException::class,NoSuchAlgorithmException::class,NoSuchProviderException::class,InvalidAlgorithmParameterException::class)privatefuncreateAndStoreSecretKey(){valbuilder:KeyGenParameterSpec.Builder=KeyGenParameterSpec.Builder(ANDROID_KEY_STORE_ALIAS,KeyProperties.PURPOSE_ENCRYPTorKeyProperties.PURPOSE_DECRYPT)valkeySpec:KeyGenParameterSpec=builder.setKeySize(256).setBlockModes(KeyProperties.BLOCK_MODE_GCM).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE).setRandomizedEncryptionRequired(true).build()valaesKeyGenerator:KeyGenerator=KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,ANDROID_KEY_STORE_PROVIDER)aesKeyGenerator.init(keySpec)valkey:SecretKey=aesKeyGenerator.generateKey()}@Throws(KeyStoreException::class,UnrecoverableEntryException::class,NoSuchAlgorithmException::class,CertificateException::class,IOException::class,NoSuchPaddingException::class,InvalidKeyException::class,IllegalBlockSizeException::class,BadPaddingException::class)privatefunencryptWithKeyStore(plainText:String):ByteArray? {// Initialize KeyStorevalkeyStore:KeyStore=KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER)keyStore.load(null)// Retrieve the key with alias androidKeyStoreAlias created beforevalkeyEntry:KeyStore.SecretKeyEntry=keyStore.getEntry(ANDROID_KEY_STORE_ALIAS,null)asKeyStore.SecretKeyEntryvalkey:SecretKey=keyEntry.secretKey// Use the secret key at your conveniencevalcipher:Cipher=Cipher.getInstance("AES/GCM/NoPadding")cipher.init(Cipher.ENCRYPT_MODE,key)returncipher.doFinal(plainText.toByteArray())}
Java
staticprivatefinalStringANDROID_KEY_STORE_PROVIDER="AndroidKeyStore";staticprivatefinalStringANDROID_KEY_STORE_ALIAS="AES_KEY_DEMO";privatevoidcreateAndStoreSecretKey()throwsKeyStoreException,NoSuchAlgorithmException,NoSuchProviderException,InvalidAlgorithmParameterException{KeyGenParameterSpec.Builderbuilder=newKeyGenParameterSpec.Builder(ANDROID_KEY_STORE_ALIAS,KeyProperties.PURPOSE_ENCRYPT|KeyProperties.PURPOSE_DECRYPT);KeyGenParameterSpeckeySpec=builder.setKeySize(256).setBlockModes(KeyProperties.BLOCK_MODE_GCM).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE).setRandomizedEncryptionRequired(true).build();KeyGeneratoraesKeyGenerator=KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,ANDROID_KEY_STORE_PROVIDER);aesKeyGenerator.init(keySpec);SecretKeykey=aesKeyGenerator.generateKey();}privatebyte[]encryptWithKeyStore(finalStringplainText)throwsKeyStoreException,UnrecoverableEntryException,NoSuchAlgorithmException,CertificateException,IOException,NoSuchPaddingException,InvalidKeyException,IllegalBlockSizeException,BadPaddingException{// Initialize KeyStoreKeyStorekeyStore=KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);keyStore.load(null);// Retrieve the key with alias ANDROID_KEY_STORE_ALIAS created beforeKeyStore.SecretKeyEntrykeyEntry=(KeyStore.SecretKeyEntry)keyStore.getEntry(ANDROID_KEY_STORE_ALIAS,null);SecretKeykey=keyEntry.getSecretKey();// Use the secret key at your conveniencefinalCiphercipher=Cipher.getInstance("AES/GCM/NoPadding");cipher.init(Cipher.ENCRYPT_MODE,key);returncipher.doFinal(plainText.getBytes());}
Le contenu et les exemples de code de cette page sont soumis aux licences décrites dans la Licence de contenu. Java et OpenJDK sont des marques ou des marques déposées d'Oracle et/ou de ses sociétés affiliées.
Dernière mise à jour le 2023/12/26 (UTC).
[[["Facile à comprendre","easyToUnderstand","thumb-up"],["J'ai pu résoudre mon problème","solvedMyProblem","thumb-up"],["Autre","otherUp","thumb-up"]],[["Il n'y a pas l'information dont j'ai besoin","missingTheInformationINeed","thumb-down"],["Trop compliqué/Trop d'étapes","tooComplicatedTooManySteps","thumb-down"],["Obsolète","outOfDate","thumb-down"],["Problème de traduction","translationIssue","thumb-down"],["Mauvais exemple/Erreur de code","samplesCodeIssue","thumb-down"],["Autre","otherDown","thumb-down"]],["Dernière mise à jour le 2023/12/26 (UTC)."],[],[],null,["# Hardcoded Cryptographic Secrets\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CRYPTO: Cryptography](https://mas.owasp.org/MASVS/06-MASVS-CRYPTO)\n\nOverview\n--------\n\n| **Note:** This article isn't focused on how to protect API keys.\n\nDevelopers use cryptography to protect confidentiality and integrity of data using robust algorithms. However, the key storage is often underused, and it's common to find them hardcoded into the application as a string or byte array in the code or in an asset file such as `strings.xml`. If secrets are exposed in any files of the app, this goes against [Kerchoff's principle](https://en.wikipedia.org/wiki/Kerckhoffs%27s_principle) and the security model can be considered as broken.\n\nImpact\n------\n\nAn attacker with access to reverse engineering tools can retrieve a hard-coded secret very easily. Depending on conditions the impact might vary, but in many cases it leads to major security issues, such as access to sensitive data.\n\nMitigations\n-----------\n\nTo mitigate this issue, consider using the [KeyChain](/reference/android/security/KeyChain) API when you want system-wide credentials, or the [Android Keystore](/training/articles/keystore) provider to let an individual app store its own credentials that only the app itself can access.\n\nThe following code snippet shows how to store and use a symmetric key using\n`KeyStore`: \n\n### Kotlin\n\n private val ANDROID_KEY_STORE_PROVIDER = \"AndroidKeyStore\"\n private val ANDROID_KEY_STORE_ALIAS = \"AES_KEY_DEMO\"\n\n @Throws(\n KeyStoreException::class,\n NoSuchAlgorithmException::class,\n NoSuchProviderException::class,\n InvalidAlgorithmParameterException::class\n )\n private fun createAndStoreSecretKey() {\n val builder: KeyGenParameterSpec.Builder = KeyGenParameterSpec.Builder(\n ANDROID_KEY_STORE_ALIAS,\n KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT\n )\n val keySpec: KeyGenParameterSpec = builder\n .setKeySize(256)\n .setBlockModes(KeyProperties.BLOCK_MODE_GCM)\n .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)\n .setRandomizedEncryptionRequired(true)\n .build()\n val aesKeyGenerator: KeyGenerator =\n KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER)\n aesKeyGenerator.init(keySpec)\n val key: SecretKey = aesKeyGenerator.generateKey()\n }\n\n @Throws(\n KeyStoreException::class,\n UnrecoverableEntryException::class,\n NoSuchAlgorithmException::class,\n CertificateException::class,\n IOException::class,\n NoSuchPaddingException::class,\n InvalidKeyException::class,\n IllegalBlockSizeException::class,\n BadPaddingException::class\n )\n private fun encryptWithKeyStore(plainText: String): ByteArray? {\n // Initialize KeyStore\n val keyStore: KeyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER)\n keyStore.load(null)\n // Retrieve the key with alias androidKeyStoreAlias created before\n val keyEntry: KeyStore.SecretKeyEntry =\n keyStore.getEntry(ANDROID_KEY_STORE_ALIAS, null) as KeyStore.SecretKeyEntry\n val key: SecretKey = keyEntry.secretKey\n // Use the secret key at your convenience\n val cipher: Cipher = Cipher.getInstance(\"AES/GCM/NoPadding\")\n cipher.init(Cipher.ENCRYPT_MODE, key)\n return cipher.doFinal(plainText.toByteArray())\n }\n\n### Java\n\n static private final String ANDROID_KEY_STORE_PROVIDER = \"AndroidKeyStore\";\n static private final String ANDROID_KEY_STORE_ALIAS = \"AES_KEY_DEMO\";\n\n private void createAndStoreSecretKey() throws KeyStoreException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {\n KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(\n ANDROID_KEY_STORE_ALIAS,\n KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);\n KeyGenParameterSpec keySpec = builder\n .setKeySize(256)\n .setBlockModes(KeyProperties.BLOCK_MODE_GCM)\n .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)\n .setRandomizedEncryptionRequired(true)\n .build();\n KeyGenerator aesKeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE_PROVIDER);\n aesKeyGenerator.init(keySpec);\n SecretKey key = aesKeyGenerator.generateKey();\n }\n\n private byte[] encryptWithKeyStore(final String plainText) throws KeyStoreException, UnrecoverableEntryException, NoSuchAlgorithmException, CertificateException, IOException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {\n // Initialize KeyStore\n KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);\n keyStore.load(null);\n // Retrieve the key with alias ANDROID_KEY_STORE_ALIAS created before\n KeyStore.SecretKeyEntry keyEntry = (KeyStore.SecretKeyEntry) keyStore.getEntry(ANDROID_KEY_STORE_ALIAS, null);\n SecretKey key = keyEntry.getSecretKey();\n // Use the secret key at your convenience\n final Cipher cipher = Cipher.getInstance(\"AES/GCM/NoPadding\");\n cipher.init(Cipher.ENCRYPT_MODE, key);\n return cipher.doFinal(plainText.getBytes());\n }\n\nResources\n---------\n\n- [Android KeyStore system](/training/articles/keystore)\n\n- [KeyStore documentation](/reference/java/security/KeyStore)\n\n- [KeyChain documentation](/reference/android/security/KeyChain)\n\n- [CWE-321: Use of Hard-coded Cryptographic Key](https://cwe.mitre.org/data/definitions/321.html)"]]