Mam program, który odczytuje informacje o serwerze z pliku konfiguracyjnego i chciałby zaszyfrować hasło w tej konfiguracji, które może zostać odczytane przez mój program i odszyfrowane.
Wymagania:
- Zaszyfruj hasło w postaci zwykłego tekstu, które ma być zapisane w pliku
- Odszyfruj zaszyfrowane hasło odczytane z pliku z mojego programu
Jakieś zalecenia, jak bym to zrobił? Myślałem o napisaniu własnego algorytmu, ale czuję, że byłby to strasznie niepewny.
java
security
encryption
configuration
cryptography
Petey B.
źródło
źródło
Odpowiedzi:
Prostym sposobem na to jest użycie szyfrowania opartego na hasłach w Javie. Pozwala to zaszyfrować i odszyfrować tekst za pomocą hasła.
Zasadniczo oznacza to zainicjowanie
javax.crypto.Cipher
algorytmu"AES/CBC/PKCS5Padding"
i uzyskanie kluczajavax.crypto.SecretKeyFactory
z"PBKDF2WithHmacSHA512"
algorytmu.Oto przykład kodu (zaktualizowany, aby zastąpić mniej bezpieczny wariant oparty 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); } }
Pozostaje jeden problem: gdzie należy przechowywać hasło, którego używasz do szyfrowania haseł? Możesz przechowywać go w pliku źródłowym i zaciemniać, ale nie jest trudno go znaleźć ponownie. Alternatywnie możesz podać ją jako właściwość systemową podczas uruchamiania procesu Java (
-DpropertyProtectionPassword=...
).Ten sam problem pozostaje, jeśli używasz KeyStore, który również jest chroniony hasłem. Zasadniczo będziesz musiał gdzieś mieć jedno hasło główne, które jest dość trudne do zabezpieczenia.
źródło
Tak, zdecydowanie nie pisz własnego algorytmu. Java ma wiele interfejsów API kryptografii.
Jeśli system operacyjny, na którym instalujesz, ma magazyn kluczy, możesz go użyć do przechowywania kluczy kryptograficznych, które będą potrzebne do zaszyfrowania i odszyfrowania poufnych danych w konfiguracji lub innych plikach.
źródło
Sprawdź jasypt , czyli bibliotekę oferującą podstawowe możliwości szyfrowania przy minimalnym wysiłku.
źródło
Myślę, że najlepszym rozwiązaniem jest upewnienie się, że plik konfiguracyjny (zawierający hasło) jest dostępny tylko dla określonego konta użytkownika . Na przykład możesz mieć użytkownika specyficznego dla aplikacji,
appuser
do którego tylko zaufane osoby mają hasło (i do którego mogąsu
).W ten sposób nie ma irytującego narzutu kryptograficznego, a nadal masz bezpieczne hasło.
EDYCJA: Zakładam, że nie eksportujesz konfiguracji aplikacji poza zaufane środowisko (co nie jestem pewien, czy miałoby to jakiś sens, biorąc pod uwagę pytanie)
źródło
Najważniejsze jest to, że słoń w pokoju i to wszystko polega na tym, że jeśli twoja aplikacja może zdobyć hasło, to haker z dostępem do skrzynki również może je zdobyć!
Jedynym sposobem obejścia tego jest to, że aplikacja pyta o „hasło główne” na konsoli przy użyciu standardowego wejścia, a następnie używa go do odszyfrowania haseł przechowywanych w pliku. Oczywiście to całkowicie uniemożliwia uruchomienie aplikacji bez nadzoru wraz z systemem operacyjnym podczas uruchamiania.
Jednak nawet przy takim poziomie irytacji, jeśli hakerowi uda się uzyskać uprawnienia administratora (lub nawet dostęp jako użytkownik uruchamiający aplikację), może zrzucić pamięć i znaleźć tam hasło.
Chodzi o to, aby nie pozwolić całej firmie na dostęp do serwera produkcyjnego (a tym samym do haseł) i upewnić się, że nie da się złamać tego pudełka!
źródło
Cóż, aby rozwiązać problemy z hasłem głównym - najlepszym podejściem jest nie przechowywanie hasła nigdzie, aplikacja powinna szyfrować hasła dla siebie - tak, aby tylko ona mogła je odszyfrować. Więc gdybym używał pliku .config, zrobiłbym co następuje, mySettings.config :
więc wczytałbym klucze, które są wymienione w encryptTheseKeys, zastosowałem na nich przykład Brodwalls z góry i zapisałem je z powrotem do pliku z jakimś znacznikiem (powiedzmy crypt :), aby aplikacja wiedziała, że tego nie robi znowu wynik będzie wyglądał następująco:
Tylko pamiętaj, aby przechowywać oryginały w swoim własnym, bezpiecznym miejscu ...
źródło
Spróbuj użyć metod szyfrowania ESAPI. Jest łatwy w konfiguracji, a także możesz łatwo zmienić klucze.
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
ty
1) zaszyfrować 2) odszyfrować 3) podpisać 4) zrezygnować z podpisu 5) haszować 6) podpisy czasowe i wiele więcej za pomocą tylko jednej biblioteki.
źródło
Zobacz, co jest dostępne w Jetty do przechowywania haseł (lub skrótów) w plikach konfiguracyjnych i zastanów się, czy kodowanie OBF może być dla Ciebie przydatne. Następnie zobacz w źródle, jak to się robi.
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
źródło
W zależności od tego, jak bezpieczne są potrzebne pliki konfiguracyjne lub jak niezawodna jest Twoja aplikacja, http://activemq.apache.org/encrypted-passwords.html może być dla Ciebie dobrym rozwiązaniem.
Jeśli nie boisz się odszyfrowania hasła i skonfigurowanie go przy użyciu fasoli do przechowywania klucza hasła może być naprawdę proste. Jeśli jednak potrzebujesz większego bezpieczeństwa, możesz ustawić zmienną środowiskową z sekretem i usunąć ją po uruchomieniu. W związku z tym musisz się martwić, że aplikacja / serwer przestanie działać, a nie aplikacja, która nie zostanie automatycznie uruchomiona ponownie.
źródło
Jeśli korzystasz z języka Java 8, użycie wewnętrznego kodera i dekodera Base64 można uniknąć, zastępując pliki
return new BASE64Encoder().encode(bytes);
z
return Base64.getEncoder().encodeToString(bytes);
i
return new BASE64Decoder().decodeBuffer(property);
z
return Base64.getDecoder().decode(property);
Należy pamiętać, że to rozwiązanie nie chroni danych, ponieważ metody odszyfrowywania są przechowywane w tym samym miejscu. To tylko utrudnia złamanie. Przede wszystkim unika drukowania i pokazywania wszystkim przez pomyłkę.
źródło