Шифровать пароль в файлах конфигурации?
У меня есть программа, которая считывает информацию о сервере из файла конфигурации и хочет зашифровать пароль в этой конфигурации, который может быть прочитан моей программой и дешифрован.
ТРЕБОВАНИЯ:
- Шифровать пароль открытого текста, который будет храниться в файле
- Расшифруйте зашифрованный пароль, прочитанный из файла из моей программы
Любые рекомендации о том, как я буду заниматься этим? Я думал написать собственный алгоритм, но я чувствую, что это будет ужасно неуверенно.
- Почему SSL-квитирование дает исключение «Не удалось создать DH keypair»?
- Генерация ключей шифрования / дешифрования Java openssl
- C # RSA-шифрование / дешифрование с передачей
- Регистрация нескольких хранилищ ключей в JVM
- Можно ли расшифровывать hashи md5?
- Недопустимый пробел и его нельзя удалить?
- Солить свой пароль: лучшие практики?
- Как я могу подписать файл с помощью RSA и SHA256 с .NET?
- Что случилось с расшифровкой шифрования nodejs?
- Что является самым безопасным семенем для генерации случайных чисел?
- Что делает оператор?
- Является ли вычисление хеша MD5 менее интенсивным процессором, чем функции семейства SHA?
- Какую криптографическую hash-функцию я должен выбрать?
Простой способ сделать это – использовать шифрование на основе пароля на Java. Это позволяет шифровать и расшифровывать текст с помощью пароля.
Это в основном означает инициализацию javax.crypto.Cipher
с алгоритмом "AES/CBC/PKCS5Padding"
и получение ключа от javax.crypto.SecretKeyFactory
с "PBKDF2WithHmacSHA512"
алгоритма "PBKDF2WithHmacSHA512"
.
Вот пример кода (обновленный для замены менее безопасного варианта на основе 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="); } // 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); } }
Остается одна проблема: где вы должны хранить пароль, который вы используете для шифрования паролей? Вы можете сохранить его в исходном файле и обфускать его, но его не так уж сложно найти. В качестве альтернативы вы можете -DpropertyProtectionPassword=...
его как системное свойство при запуске Java-процесса ( -DpropertyProtectionPassword=...
).
Эта же проблема сохраняется, если вы используете KeyStore, который также защищен паролем. В принципе, вам понадобится один мастер-пароль, и его довольно сложно защитить.
Да, определенно не пишите свой собственный алгоритм. Java имеет множество криптографических API.
Если ОС, на которую вы устанавливаете приложение, имеет хранилище ключей, вы можете использовать это для хранения ключей криптографии, которые вам необходимы для шифрования и дешифрования конфиденциальных данных в вашей конфигурации или других файлах.
Проверьте jasypt , которая представляет собой библиотеку, предлагающую базовые возможности шифрования с минимальными усилиями.
Я считаю, что лучший подход – обеспечить, чтобы ваш файл конфигурации (содержащий ваш пароль) был доступен только для определенной учетной записи пользователя . Например, у вас может быть пользовательский пользовательский appuser
для которого только доверенные люди имеют пароль (и к которому они su
).
Таким образом, нет назойливой криптографии, и у вас все еще есть безопасный пароль.
EDIT: Я предполагаю, что вы не экспортируете конфигурацию своего приложения за пределы надежной среды (что я не уверен, что это будет иметь смысл, учитывая вопрос)
Ну, чтобы решить проблемы мастер-пароля – лучший подход – не хранить пароль нигде, приложение должно шифровать пароли для себя – чтобы только он мог их расшифровать. Поэтому, если бы я использовал файл .config, я бы сделал следующее: mySettings.config :
encryptTheseKeys = SecretKey, anotherSecret
SecretKey = unprotectedPasswordThatIputHere
anotherSecret = anotherPass
someKey = unprotectedSettingIdontCareAbout
поэтому я бы прочитал в ключах, которые упоминаются в encryptTheseKeys, примените пример Brodwalls сверху на них и запишите их обратно в файл с каким-либо маркером (скажем, crypt :), чтобы приложение не могло этого сделать снова результат будет выглядеть так:
encryptTheseKeys = SecretKey, anotherSecret
secretKey = crypt: ii4jfj304fjhfj934fouh938
anotherSecret = crypt: jd48jofh48h
someKey = unprotectedSettingIdontCareAbout
Просто убедитесь, что вы сохранили оригиналы в своем безопасном месте …
Большая точка, и слон в комнате, и все такое, заключается в том, что если ваше приложение может получить пароль, тогда хакер, имеющий доступ к коробке, сможет его удержать!
Единственным способом, связанным с этим, является то, что приложение запрашивает «главный пароль» на консоли с использованием стандартного ввода, а затем использует его для дешифрования паролей, хранящихся в файле. Конечно, это полностью исключает возможность запуска приложения без присмотра вместе с ОС при загрузке.
Однако даже при таком уровне раздражения, если хакеру удается получить root-доступ (или даже просто получить доступ как пользователь, запускающий ваше приложение), он может сбросить память и найти там пароль.
Дело в том, чтобы не допустить, чтобы вся компания имела доступ к серверу производства (и тем самым к паролям) и следила за тем, чтобы эту коробку не удалось взломать!
Попробуйте использовать методы шифрования ESAPI. Его легко настроить, и вы также можете легко изменить свои ключи.
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
Вы
1) шифровать 2) расшифровывать 3) знак 4) unsign 5) хешировать 6) сигнатуры, основанные на времени, и многое другое только с одной библиотекой.
Посмотрите, что доступно в Jetty для хранения пароля (или hashей) в файлах конфигурации, и подумайте, может ли быть использована 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);
Обратите внимание, что это решение не защищает ваши данные, поскольку методы дешифрования хранятся в одном месте. Это просто усложняет разрыв. В основном это позволяет избежать печати и показать его всем по ошибке.