Chiffrer le mot de passe dans les Fichiers de configuration? [fermé]


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 lu par mon programme et déchiffré.

Requirments:

  • Crypter le mot de passe en texte brut à stocker dans le fichier
  • Déchiffrez le mot de passe crypté lu à partir du fichier de mon programme

Des recommandations sur la façon dont je ferais cela? Je pensais écrire mon propre algorithme mais je pense que ce serait terriblement précaire.

Author: Artjom B., 2009-07-15

10 answers

Une façon simple de le faire est d'utiliser le cryptage basé sur un mot de passe en Java. Cela vous permet de chiffrer et de déchiffrer un texte à l'aide d'un mot de passe.

Ceci signifie fondamentalement l'initialisation d'un javax.crypto.Cipher avec l'algorithme de "AES/CBC/PKCS5Padding" et obtenir une clé de javax.crypto.SecretKeyFactory avec "PBKDF2WithHmacSHA512" algorithme.

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

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(String[] args) throws Exception {
        String password = System.getProperty("password");
        if (password == null) {
            throw new IllegalArgumentException("Run with -Dpassword=<password>");
        }

        // The salt (probably) can be stored along with the encrypted data
        byte[] salt = new String("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);

        String originalPassword = "secret";
        System.out.println("Original password: " + originalPassword);
        String encryptedPassword = encrypt(originalPassword, key);
        System.out.println("Encrypted password: " + encryptedPassword);
        String 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 String encrypt(String 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 String base64Encode(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    private static String decrypt(String string, SecretKeySpec key) throws GeneralSecurityException, IOException {
        String iv = string.split(":")[0];
        String property = string.split(":")[1];
        Cipher pbeCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        pbeCipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(base64Decode(iv)));
        return new String(pbeCipher.doFinal(base64Decode(property)), "UTF-8");
    }

    private static byte[] base64Decode(String property) throws IOException {
        return Base64.getDecoder().decode(property);
    }
}

Un problème demeure: 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 l'obscurcir, mais il n'est pas trop difficile de le retrouver. Alternativement, vous pouvez lui 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 magasin de clés, qui est également protégé par un mot de passe. Fondamentalement, vous aurez besoin d'avoir un mot de passe maître, quelque part, et c'est assez difficile à protéger.

 154
Author: Johannes Brodwall, 2018-01-11 21:42:54

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

Si le système d'exploitation sur lequel vous installez a un magasin de clés, vous pouvez l'utiliser pour stocker vos clés cryptographiques dont vous aurez besoin pour crypter et déchiffrer les données sensibles dans votre configuration ou d'autres fichiers.

 20
Author: JeeBee, 2009-07-15 16:50:45

Consultezjasypt , qui est une bibliothèque offrant des capacités de chiffrement de base avec un minimum d'effort.

 18
Author: Kaitsu, 2012-06-27 12:21:47

Je pense que la meilleure approche est de s'assurer que votre fichier de configuration (contenant votre mot de passe) est , accessibles uniquement à un compte d'utilisateur spécifique. Par exemple, vous pouvez avoir un utilisateur spécifique à l'application appuser auquel seules les personnes de confiance ont le mot de passe (et auquel elles 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é.

MODIFIER: Je suppose que vous n'exportez pas votre application configuration en dehors d'un environnement de confiance (ce qui, je ne suis pas sûr, n'aurait aucun sens, compte tenu de la question)

 15
Author: oxbow_lakes, 2009-07-15 17:26:24

Eh bien pour résoudre les problèmes de mot de passe maître - la meilleure approche est de ne pas stocker le mot de passe n'importe où, l'application doit crypter les mots de passe pour elle - même-afin que seule elle puisse les déchiffrer. Donc, si j'ai été en utilisant un .fichier de configuration Je ferais ce qui suit, mySettings.configuration :

EncryptTheseKeys=secretKey, anotherSecret

SecretKey=unprotectedPasswordThatIputHere

AnotherSecret=anotherPass

SomeKey=unprotectedSettingIdontCareAbout

Donc je lirais dans les clés qui sont mentionnées dans le encryptTheseKeys, appliquer l'exemple Brodwalls d'en haut sur eux et écrivez-les dans le fichier avec un marqueur quelconque (disons crypt: ) pour que l'application sache ne pas le refaire, la sortie ressemblerait à ceci:

EncryptTheseKeys=secretKey, anotherSecret

SecretKey=crypte:ii4jfj304fjhfj934fouh938

AnotherSecret=crypte:jd48jofh48h

SomeKey=unprotectedSettingIdontCareAbout

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

 4
Author: user1007231, 2012-01-17 22:18:30

Le gros point, et l'éléphant dans la pièce et tout ça, c'est que si votre application peut mettre la main sur le mot de passe, alors un pirate ayant accès à la boîte peut aussi mettre la main dessus!

Le seul moyen de contourner ce problème est que l'application demande le "mot de passe principal" sur la console à l'aide d'une entrée standard, puis l'utilise pour déchiffrer 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 OS quand il démarre.

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

La chose à assurer, c'est de ne pas laisser toute l'entreprise avoir accès au serveur de production (et donc aux mots de passe), et de s'assurer qu'il est impossible de casser cette boîte!

 4
Author: stolsvik, 2013-10-06 19:32:05

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

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

Vous

1)chiffrer 2)décrypter 3)inscrivez-vous 4)unsign 5) hachage 6) signatures basées sur le temps et bien plus encore avec une seule bibliothèque.

 1
Author: Rohit Salecha, 2012-12-05 07:12:33

Voyez ce qui est disponible dans Jetty pour stocker le mot de passe (ou les hachages) dans les fichiers de configuration, et considérez si l'encodage OBF pourrait vous être utile. Ensuite, voyez dans la source comment cela se fait.

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

 1
Author: Thorbjørn Ravn Andersen, 2014-12-12 16:11:28

En fonction de la sécurité dont vous avez besoin des fichiers de configuration ou de 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 que le mot de passe soit déchiffré et qu'il peut être très simple à configurer en utilisant un bean pour stocker la clé de mot de passe. Toutefois, si vous avez besoin de plus de sécurité, vous pouvez définir une variable d'environnement avec le secret et l'enlever après le lancement. Avec cela, vous devez vous soucier de la application / serveur en panne et non l'application ne se relance pas automatiquement.

 0
Author: CPrescott, 2014-01-07 22:02:14

Si vous utilisez java 8 {[6] } 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().encodeToString(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 à casser. Surtout, il évite de l'imprimer et de le montrer à tout le monde en erreur.

 -5
Author: Antonio Raposo, 2015-01-23 17:39:43