web-dev-qa-db-fra.com

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

Requirments:

  • Crypter le mot de passe en clair pour être stocké dans le fichier
  • Décrypter le mot de passe crypté lu dans le fichier de mon programme

Des recommandations sur la façon dont je m'y prendrais? Je pensais écrire mon propre algorithme mais je pense que ce serait terriblement peu sûr.

125
Petey B

Une méthode simple consiste à utiliser le cryptage basé sur les mots de passe en Java. Cela vous permet de chiffrer et de déchiffrer un texte à l'aide d'un mot de passe.

Cela signifie essentiellement initialiser un javax.crypto.Cipher avec l'algorithme "AES/CBC/PKCS5Padding" et obtenir une clé de javax.crypto.SecretKeyFactory avec le "PBKDF2WithHmacSHA512" algorithme.

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(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ù devriez-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 ce n'est pas si difficile de le retrouver. Vous pouvez également le définir comme 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. En gros, vous aurez besoin d’un mot de passe principal quelque part, et il est très difficile à protéger.

163
Johannes Brodwall

Oui, n'écrivez certainement pas votre propre algorithme. Java possède de nombreuses API de cryptographie.

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

20
JeeBee

Check out jasypt , une bibliothèque offrant des capacités de cryptage de base avec un minimum d'effort.

18
Christophe

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 spécifique à l’application appuser auquel seules les personnes de confiance ont le mot de passe (et auquel elles su correspond).

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

EDIT: Je suppose que vous n'exportez pas la configuration de votre application en dehors d'un environnement sécurisé (ce qui, à mon avis, n'aurait aucun sens, étant donné la question)

16
oxbow_lakes

Bien pour résoudre les problèmes de mot de passe principal - la meilleure approche consiste à ne pas stocker le mot de passe où que ce soit, l'application doit chiffrer les mots de passe pour elle-même - afin qu'elle seule puisse les déchiffrer. Donc, si j'utilisais un fichier .config, je ferais ce qui suit, mySettings.config :

encryptTheseKeys = secretKey, une autreSecret

secretKey = unsotectedPasswordThatIputHere

anotherSecret = anotherPass

someKey = unsotectedSettingIdontCareAbout

je voudrais donc lire les clés mentionnées dans encryptTheseKeys, appliquer l’exemple de Brodwalls d’en haut et les écrire dans le fichier avec un marqueur quelconque (disons crypt :) pour que l'application sache que cela ne se reproduira plus, la sortie ressemblerait à ceci:

encryptTheseKeys = secretKey, une autreSecret

secretKey = crypt: ii4jfj304fjhfj934fouh938

anotherSecret = crypt: jd48jofh48h

someKey = unsotectedSettingIdontCareAbout

Assurez-vous simplement de conserver les originaux dans votre propre lieu sécurisé ...

4
user1007231

Le gros problème, ainsi que l’éléphant dans la pièce et tout le reste, est que si votre application peut obtenir le mot de passe, alors un pirate informatique ayant accès à la boîte peut l’obtenir également!

Le seul moyen de contourner ce problème est que l'application demande le "mot de passe principal" sur la console à l'aide de l'entrée standard, puis l'utilise pour déchiffrer les mots de passe stockés dans le fichier. Bien entendu, il est impossible de lancer l’application sans surveillance avec le système d’exploitation lors du démarrage.

Cependant, même avec ce niveau de contrariété, si un pirate informatique 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 à faire est de ne pas laisser toute la société avoir accès au serveur de production (et donc aux mots de passe), et assurez-vous qu'il est impossible de déchiffrer cette boîte!

4
stolsvik

Voyez ce qui est disponible dans Jetty pour stocker le mot de passe (ou les hachages) dans les fichiers de configuration et déterminez si le codage OBF peut 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

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

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

Toi

1) crypter 2) décrypter 3) signer 4) annuler la signature 5) hacher 6) les signatures basées sur le temps et bien plus encore avec une seule bibliothèque.

1
Rohit Salecha

Selon votre niveau de sécurité des 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'êtes pas trop effrayé par le déchiffrement du mot de passe, il peut être très simple de le 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 la supprimer après son lancement. Avec cela, vous devez vous inquiéter de la panne de l'application/du serveur et éviter que l'application ne soit pas automatiquement relancée.

0
CPrescott