Cifrar a senha nos ficheiros de configuração? [fechado]

Tenho um programa que lê as informações do servidor a partir de um ficheiro de configuração e gostaria de cifrar a senha nessa configuração que pode ser lida pelo meu programa e descodificada.

Requisitos:

  • encriptar a senha de texto simples a guardar no ficheiro
  • descodificar a senha encriptada lida do ficheiro do meu programa
Alguma recomendação sobre como eu faria isto? Estava a pensar escrever o meu próprio algoritmo, mas sinto-o. seria terrivelmente inseguro.

Author: Artjom B., 2009-07-15

10 answers

Uma forma simples de fazer isto é usar a encriptação baseada em senha em Java. Isto permite-lhe cifrar e descodificar um texto usando uma senha.

Isto basicamente significa inicializar um javax.crypto.Cipher com o algoritmo "AES/CBC/PKCS5Padding" e obter uma chave de javax.crypto.SecretKeyFactory com o algoritmo "PBKDF2WithHmacSHA512".

Aqui está um exemplo de código (actualizado para substituir a variante menos segura baseada na 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);
    }
}

Resta um problema: onde deve guardar a senha que usa para cifrar as senhas? Você pode armazenar está no arquivo fonte e ofuscá-lo, mas não é muito difícil encontrá-lo novamente. Alternativamente, você pode dar-lhe como uma propriedade do sistema quando você iniciar o processo Java (-DpropertyProtectionPassword=...).

O mesmo problema permanece se você usar o teclado, que também está protegido por uma senha. Basicamente, você vai precisar de ter uma senha mestre em algum lugar, e é muito difícil de proteger.

 154
Author: Johannes Brodwall, 2018-01-11 21:42:54
Sim, definitivamente Não escrevas o teu próprio algoritmo. Java tem muitas APIs de criptografia.

Se o SO em que está a instalar tiver um teclado, então poderá usá-lo para guardar as suas chaves de cifra que terá de cifrar e descodificar os dados sensíveis na sua configuração ou noutros ficheiros.

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

Confirajasypt , que é uma biblioteca que oferece capacidades básicas de encriptação com esforço mínimo.

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

Penso que a melhor abordagem é assegurar que o seu ficheiro de configuração (que contém a sua senha) seja apenas Acessível a uma conta de utilizador específica. Por exemplo, você pode ter um usuário específico da aplicação appuser para o qual apenas as pessoas de confiança têm a senha (e para a qual su têm).

Assim, não há criptografia irritante e ainda tens uma senha segura.

Editar: presumo que não esteja a exportar a sua configuração da aplicação fora de um ambiente de confiança (o que Não tenho certeza faria qualquer sentido, dada a questão)

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

Bem, para resolver os problemas da senha mestre-a melhor abordagem é não armazenar a senha em qualquer lugar, a aplicação deve criptografar senhas para si mesma - de modo que só ele pode descriptografá-las. Então, se eu estivesse a usar um .config file eu faria o seguinte, mySettings.configuração:

Encriptar os Keys=secretKey, outro segredo

SecretKey=unprotected sasswordthather

Outro segredo=outro saco

SomeKey=unprotectedSettingIdontCareAbout

Então eu leria nas chaves que são mencionadas no encriptar as teclas, aplicar o exemplo das 'brochuras' a partir de cima sobre elas e escreva-os de volta para o ficheiro com um marcador de algum tipo (vamos dizer crypt: ) para que a aplicação saiba que não o fará de novo, o resultado ficaria assim:

Encriptar os Keys=secretKey, outro segredo

SecretKey= crypt: ii4jfj304fjhfj934fouh938

Outro segredo= cripta: jd48jofh48h

SomeKey=unprotectedSettingIdontCareAbout

Certifica-te apenas de manter os originais no teu próprio lugar seguro...
 4
Author: user1007231, 2012-01-17 22:18:30
O grande ponto, e o elefante na sala e tudo isso, é que se a sua aplicação conseguir a senha, então um hacker com acesso à caixa também a pode ter!

A única maneira de contornar isto, é que a aplicação pede a "senha mestre" na consola, usando a entrada padrão, e então usa isto para descodificar as senhas armazenadas no ficheiro. É claro que isso torna completamente impossível ter o início da aplicação sem supervisão, juntamente com o SO quando ele Botas.

No entanto, mesmo com este nível de aborrecimento, se um hacker consegue obter acesso root (ou mesmo apenas acesso como o utilizador que executa a sua aplicação), ele pode descarregar a memória e encontrar a senha lá.

A coisa a garantir, é não deixar toda a empresa ter acesso ao servidor de produção (e, assim, às senhas), e certifique-se de que é impossível quebrar esta caixa!

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

Tenta usar os métodos de encriptação do ESAPIs. É fácil de configurar e você também pode facilmente mudar suas chaves.

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

Tu

1)cifrar 2)descodificar 3) sinal 4)sinal 5)amarração 6) assinaturas baseadas no tempo e muito mais com apenas uma biblioteca.

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

Veja o que está disponível no Jetty para armazenar senha (ou traços) em arquivos de configuração, e considere se a codificação OBF pode ser útil para você. Então veja na fonte como é feito.

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

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

Dependendo da segurança dos ficheiros de configuração ou da fiabilidade da sua aplicação, http://activemq.apache.org/encrypted-passwords.html pode ser uma boa solução para ti.

Se você não tiver muito medo da senha ser decifrada e pode ser muito simples configurar usando um feijão para armazenar a chave de senha. No entanto, se você precisar de mais segurança, você pode definir uma variável de ambiente com o segredo e removê-lo após o lançamento. Com isso você tem que se preocupar sobre a aplicação / servidor a descer e não a aplicação não a relançar automaticamente.

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

Se estiver a utilizar java 8 , a utilização do codificador e descodificador interno Base64 pode ser evitada substituindo

return new BASE64Encoder().encode(bytes);

Com

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

E

return new BASE64Decoder().decodeBuffer(property);

Com

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

Note que esta solução não protege os seus dados, uma vez que os métodos de descodificação são armazenados no mesmo local. Só torna mais difícil partir. Principalmente evita imprimi-lo e mostrá-lo a todos por engano.

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