Crypter le mot de passe dans les fichiers de configuration?

J’ai un programme qui lit les informations du serveur à partir d’un fichier de configuration et souhaite chiffrer le mot de passe dans cette configuration qui peut être lue par mon programme et déchiffrée.

Conditions:

  • Crypter le mot de passe en texte brut à stocker dans le fichier
  • Déchiffrer le mot de passe crypté lu depuis le fichier depuis mon programme

Des recommandations sur la façon dont je pourrais y arriver? Je pensais écrire mon propre algorithme, mais je pense que ce serait très dangereux.

Une méthode simple consiste à utiliser le cryptage par mot de passe en Java. Cela vous permet de chiffrer et de déchiffrer un texte en utilisant un mot de passe.

Cela signifie essentiellement l’initialisation d’un javax.crypto.Cipher avec l’algorithme "AES/CBC/PKCS5Padding" et l’obtention d’une clé de javax.crypto.SecretKeyFactory avec l’algorithme "PBKDF2WithHmacSHA512" .

Voici un exemple de code (mis à jour pour remplacer la variante moins sécurisée basée sur MD5):

 import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.SecretKeySpec; public class ProtectedConfigFile { public static void main(Ssortingng[] args) throws Exception { Ssortingng password = System.getProperty("password"); if (password == null) { throw new IllegalArgumentException("Run with -Dpassword="); } // The salt (probably) can be stored along with the encrypted data byte[] salt = new Ssortingng("12345678").getBytes(); // Decreasing this speeds down startup time and can be useful during testing, but it also makes it easier for brute force attackers int iterationCount = 40000; // Other values give me java.security.InvalidKeyException: Illegal key size or default parameters int keyLength = 128; SecretKeySpec key = createSecretKey(password.toCharArray(), salt, iterationCount, keyLength); Ssortingng originalPassword = "secret"; System.out.println("Original password: " + originalPassword); Ssortingng encryptedPassword = encrypt(originalPassword, key); System.out.println("Encrypted password: " + encryptedPassword); Ssortingng decryptedPassword = decrypt(encryptedPassword, key); System.out.println("Decrypted password: " + decryptedPassword); } private static SecretKeySpec createSecretKey(char[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeySpecException { SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512"); PBEKeySpec keySpec = new PBEKeySpec(password, salt, iterationCount, keyLength); SecretKey keyTmp = keyFactory.generateSecret(keySpec); return new SecretKeySpec(keyTmp.getEncoded(), "AES"); } private static Ssortingng encrypt(Ssortingng property, SecretKeySpec key) throws GeneralSecurityException, UnsupportedEncodingException { Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); pbeCipher.init(Cipher.ENCRYPT_MODE, key); AlgorithmParameters parameters = pbeCipher.getParameters(); IvParameterSpec ivParameterSpec = parameters.getParameterSpec(IvParameterSpec.class); byte[] cryptoText = pbeCipher.doFinal(property.getBytes("UTF-8")); byte[] iv = ivParameterSpec.getIV(); return base64Encode(iv) + ":" + base64Encode(cryptoText); } private static Ssortingng base64Encode(byte[] bytes) { return Base64.getEncoder().encodeToSsortingng(bytes); } private static Ssortingng decrypt(Ssortingng ssortingng, SecretKeySpec key) throws GeneralSecurityException, IOException { Ssortingng iv = ssortingng.split(":")[0]; Ssortingng property = ssortingng.split(":")[1]; Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv))); return new Ssortingng(pbeCipher.doFinal(base64Decode(property)), "UTF-8"); } private static byte[] base64Decode(Ssortingng property) throws IOException { return Base64.getDecoder().decode(property); } } 

Un problème persiste: où devez-vous stocker le mot de passe que vous utilisez pour chiffrer les mots de passe? Vous pouvez le stocker dans le fichier source et le masquer, mais il n’est pas trop difficile de le retrouver. Vous pouvez également le donner en tant que propriété système lorsque vous démarrez le processus Java ( -DpropertyProtectionPassword=... ).

Le même problème persiste si vous utilisez le KeyStore, qui est également protégé par un mot de passe. Fondamentalement, vous aurez besoin d’un mot de passe principal quelque part, et c’est assez difficile à protéger.

Oui, n’écrivez pas votre propre algorithme. Java a beaucoup d’API de cryptographie.

Si le système d’exploitation sur lequel vous effectuez l’installation possède un fichier de clés, vous pouvez l’utiliser pour stocker vos clés de chiffrement nécessaires pour chiffrer et déchiffrer les données sensibles de votre configuration ou d’autres fichiers.

Découvrez jasypt , une bibliothèque offrant des capacités de cryptage de base avec un minimum d’effort.

Je pense que la meilleure approche est de s’assurer que votre fichier de configuration (contenant votre mot de passe) est uniquement accessible à un compte utilisateur spécifique . Par exemple, vous pouvez avoir un utilisateur appuser spécifique à l’ appuser auquel seules les personnes de confiance ont le mot de passe (et auquel ils doivent su ).

De cette façon, il n’y a pas de surcharge de cryptographie ennuyeuse et vous avez toujours un mot de passe qui est sécurisé.

EDIT: Je suppose que vous n’exportez pas votre configuration d’application en dehors d’un environnement de confiance (ce qui, je ne suis pas sûr, aurait du sens, vu la question)

Bien pour résoudre les problèmes de mot de passe principal – la meilleure approche est de ne pas stocker le mot de passe n’importe où, l’application doit chiffrer les mots de passe pour qu’elle seule puisse les déchiffrer. Donc, si j’utilisais un fichier .config, je ferais ce qui suit, mySettings.config :

encryptTheseKeys = secretKey, anotherSecret

secretKey = unprotectedPasswordThatIputHere

anotherSecret = anotherPass

someKey = non protégéSettingIdontCareAbout

Je lis donc les clés mentionnées dans l’encryptTheseKeys, leur applique l’exemple de Brodwalls et les réinscris dans le fichier avec un marqueur quelconque (disons crypt 🙂 pour laisser l’application ne pas le faire encore une fois, la sortie ressemblerait à ceci:

encryptTheseKeys = secretKey, anotherSecret

secretKey = crypte: ii4jfj304fjhfj934fouh938

anotherSecret = crypte: jd48jofh48h

someKey = non protégéSettingIdontCareAbout

Assurez-vous de garder les originaux dans votre propre endroit sécurisé …

Le gros point, et l’éléphant dans la pièce et tout ça, c’est que si votre application peut obtenir le mot de passe, alors un pirate ayant access à la boîte peut aussi s’en emparer!

Le seul moyen de contourner ce problème est que l’application demande le “mot de passe principal” sur la console en utilisant l’entrée standard, puis l’utilise pour décrypter les mots de passe stockés dans le fichier. Bien sûr, cela rend complètement impossible le démarrage de l’application sans surveillance avec le système d’exploitation au démarrage.

Cependant, même avec ce niveau de gêne, si un pirate parvient à obtenir un access root (ou même à accéder en tant qu’utilisateur exécutant votre application), il peut vider la mémoire et y trouver le mot de passe.

La chose à faire est de ne pas laisser toute la société accéder au serveur de production (et donc aux mots de passe), et de s’assurer qu’il est impossible de casser cette boîte!

Essayez d’utiliser les méthodes de chiffrement ESAPI. Il est facile à configurer et vous pouvez facilement changer vos clés.

http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html

Toi

1) chiffrer 2) déchiffrer 3) signer 4) ne pas signer 5) hacher 6) signatures basées sur le temps et beaucoup plus avec une seule bibliothèque.

Voir ce qui est disponible dans Jetty pour stocker le mot de passe (ou les hachages) dans les fichiers de configuration et déterminer si le codage OBF peut vous être utile. Ensuite, voyez dans la source comment c’est fait.

http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html

Selon la sécurité dont vous avez besoin pour les fichiers de configuration ou la fiabilité de votre application, http://activemq.apache.org/encrypted-passwords.html peut être une bonne solution pour vous.

Si vous n’avez pas trop peur du déchiffrement du mot de passe et qu’il peut être très simple de le configurer en utilisant un bean pour stocker la clé de mot de passe. Cependant, si vous avez besoin de plus de sécurité, vous pouvez définir une variable d’environnement avec le secret et la supprimer après le lancement. Avec cela, vous devez vous soucier de la mise hors service de l’application / du serveur et non de la relance automatique de l’application.

Si vous utilisez Java 8, l’utilisation de l’encodeur et du décodeur Base64 internes peut être évitée en remplaçant

return new BASE64Encoder().encode(bytes);

avec

return Base64.getEncoder().encodeToSsortingng(bytes);

et

return new BASE64Decoder().decodeBuffer(property);

avec

return Base64.getDecoder().decode(property);

Notez que cette solution ne protège pas vos données car les méthodes de décryptage sont stockées au même endroit. Cela rend juste plus difficile de casser. Principalement, cela évite de l’imprimer et de le montrer à tout le monde par erreur.