Шифровать пароль в конфигурационных файлах? [закрытый]



У меня есть программа, которая считывает информацию о сервере из файла конфигурации и хотела бы зашифровать пароль в этой конфигурации, который может быть прочитан моей программой и расшифрован.



требования:




  • зашифровать пароль открытого текста, который будет храниться в файле

  • расшифровать зашифрованный пароль, считанный из файла из моей программы


любые рекомендации о том, как я буду это делать? Я думал написать свой собственный но я чувствую, что это было бы ужасно небезопасно.

831   10  

10 ответов:

простой способ сделать это-использовать шифрование на основе пароля в Java. Это позволяет шифровать и расшифровывать текст с помощью пароля.

это в основном означает инициализацию a javax.crypto.Cipher алгоритм "AES/CBC/PKCS5Padding" и получить ключ от javax.crypto.SecretKeyFactory С .

вот пример кода (обновлен для замены менее безопасного варианта на основе 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);
    }
}

одна проблема остается: где вы храните пароль, который вы используете для шифровать пароли? Вы можете сохранить его в исходном файле и запутать его, но это не слишком трудно найти его снова. Кроме того, вы можете дать его в качестве системного свойства при запуске процесса Java (-DpropertyProtectionPassword=...).

та же проблема остается, если вы используете хранилище ключей, которое также защищено паролем. В принципе, вам нужно будет иметь один мастер-пароль где-то, и это довольно трудно защитить.

Да, определенно не пишите свой собственный алгоритм. Java имеет множество криптографических API.

Если ОС, которую вы устанавливаете, имеет хранилище ключей, вы можете использовать его для хранения своих криптографических ключей, которые вам понадобятся для шифрования и расшифровки конфиденциальных данных в вашей конфигурации или других файлах.

проверить jasypt, которая представляет собой библиотеку, предлагающую основные возможности шифрования с минимальными усилиями.

Я думаю, что лучший подход, чтобы гарантировать, что ваш конфигурационный файл (содержащий ваш пароль)доступно только для конкретной учетной записи пользователя. Например, у вас может быть конкретный пользователь приложения appuser к которому только доверенные люди имеют пароль (и к которому они su to).

таким образом, нет никаких раздражающих криптографических накладных расходов, и у вас все еще есть пароль, который является безопасным.

EDIT:Я предполагаю, что вы не экспортируйте конфигурацию приложения за пределы доверенной среды (что, я не уверен, будет иметь какой-либо смысл, учитывая вопрос)

ну, чтобы решить проблемы мастер-пароля-лучший подход не хранить пароль в любом месте, приложение должно шифровать пароли для себя-так что только он может расшифровать их. Так что если бы я использовал a .конфигурационный файл я бы сделал следующее,mySettings.конфигурации:

encryptTheseKeys=secretKey, anotherSecret

secretKey=unprotectedPasswordThatIputHere

anotherSecret=anotherPass

someKey=unprotectedSettingIdontCareAbout

поэтому я бы прочитал в ключах, которые упомянуты в encryptTheseKeys, применить пример Brodwalls сверху на них и запишите их обратно в файл с помощью какого-то маркера (скажем crypt:) чтобы приложение знало, что не нужно делать это снова, вывод будет выглядеть так:

encryptTheseKeys=secretKey, anotherSecret

secretKey=крипта: ii4jfj304fjhfj934fouh938

anotherSecret=crypt:jd48jofh48h

someKey=unprotectedSettingIdontCareAbout

просто убедитесь, что оригиналы хранятся в вашем собственном безопасном месте...

самое главное, и слон в комнате и все такое, это то, что если ваше приложение может получить пароль, то хакер с доступом к коробке может получить его тоже!

единственный способ несколько обойти это, является то, что приложение запрашивает "мастер-пароль" на консоли с помощью стандартного ввода, а затем использует это для расшифровки паролей, хранящихся в файле. Конечно, это полностью делает невозможным запуск приложения без присмотра вместе с ОС, когда она загружается.

однако даже при таком уровне раздражения, если хакеру удается получить корневой доступ (или даже просто доступ как пользователь, запускающий ваше приложение), он может сбросить память и найти пароль там.

дело в том, чтобы убедиться, что вся компания не имеет доступа к производственному серверу (и тем самым к паролям), и убедитесь, что невозможно взломать этот ящик!

попробуйте использовать методы шифрования ESAPIs. Его легко настроить, и вы также можете легко изменить свои ключи.

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

вы

1)шифровать 2)расшифровать 3)Знак 4) unsign 5)хеширование 6) подписи на основе времени и многое другое только с одной библиотекой.

посмотрите, что доступно в Jetty для хранения пароля (или хэшей) в файлах конфигурации, и подумайте, может ли кодировка OBF быть полезной для вас. Затем посмотрите в источнике, как это делается.

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

в зависимости от того, насколько безопасны вам нужны файлы конфигурации или насколько надежно ваше приложение,http://activemq.apache.org/encrypted-passwords.html может быть хорошим решением для вас.

Если вы не слишком боитесь, что пароль будет расшифрован, и его можно очень просто настроить с помощью компонента для хранения ключа пароля. Однако, если вам нужно больше безопасности, вы можете установить переменную среды с секретом и удалить ее после запуска. С этим вы должны беспокоиться о приложении / сервере происходит вниз, а не приложение не автоматически перезапускается.

если вы используете java 8 использование внутреннего кодера и декодера Base64 можно избежать, заменив

return new BASE64Encoder().encode(bytes);

С

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

и

return new BASE64Decoder().decodeBuffer(property);

С

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

обратите внимание, что это решение не защищает ваши данные, поскольку методы расшифровки хранятся в одном и том же месте. Он просто делает его труднее взломать. В основном это позволяет избежать его печати и показать его всем по ошибке.

Comments

    Ничего не найдено.