Deweloperzy używają kryptografii do ochrony poufności i integralności danych za pomocą niezawodnych algorytmów. Jednak pamięć kluczy jest często niewykorzystywana, a klucze są często zakodowane w aplikacji jako tablica ciągów znaków lub bajtów w kodzie lub pliku zasobu, np. strings.xml. Jeśli sekrety są widoczne w jakichkolwiek plikach aplikacji, jest to niezgodne z zasadą Kerchoffa, a model zabezpieczeń można uznać za nieskuteczny.
Wpływ
Osoba atakująca, która ma dostęp do narzędzi do odwrotnego inżynierii, może bardzo łatwo pobrać zakodowany sekret. W zależności od warunków wpływ może się różnić, ale w wielu przypadkach prowadzi do poważnych problemów z bezpieczeństwem, takich jak dostęp do danych wrażliwych.
Środki zaradcze
Aby rozwiązać ten problem, rozważ użycie interfejsu API KeyChain, jeśli potrzebujesz danych logowania na poziomie systemu, lub interfejsu Android Keystore, aby umożliwić poszczególnej aplikacji przechowywanie własnych danych logowania, do których dostęp ma tylko ona.
Ten fragment kodu pokazuje, jak przechowywać i używać klucza symetrycznego za pomocą funkcji 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());}
Treść strony i umieszczone na niej fragmenty kodu podlegają licencjom opisanym w Licencji na treści. Java i OpenJDK są znakami towarowymi lub zastrzeżonymi znakami towarowymi należącymi do firmy Oracle lub jej podmiotów stowarzyszonych.
Ostatnia aktualizacja: 2025-07-26 UTC.
[[["Łatwo zrozumieć","easyToUnderstand","thumb-up"],["Rozwiązało to mój problem","solvedMyProblem","thumb-up"],["Inne","otherUp","thumb-up"]],[["Brak potrzebnych mi informacji","missingTheInformationINeed","thumb-down"],["Zbyt skomplikowane / zbyt wiele czynności do wykonania","tooComplicatedTooManySteps","thumb-down"],["Nieaktualne treści","outOfDate","thumb-down"],["Problem z tłumaczeniem","translationIssue","thumb-down"],["Problem z przykładami/kodem","samplesCodeIssue","thumb-down"],["Inne","otherDown","thumb-down"]],["Ostatnia aktualizacja: 2025-07-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)"]]