Eine einfache Möglichkeit hierfür ist die Verwendung der kennwortbasierten Verschlüsselung in Java. Auf diese Weise können Sie einen Text mit einem Kennwort verschlüsseln und entschlüsseln.
Dies bedeutet im Grunde, einen javax.crypto.Cipher
with-Algorithmus zu initialisieren "AES/CBC/PKCS5Padding"
und einen Schlüssel javax.crypto.SecretKeyFactory
mit dem "PBKDF2WithHmacSHA512"
Algorithmus abzurufen.
Hier ist ein Codebeispiel (aktualisiert, um die weniger sichere MD5-basierte Variante zu ersetzen):
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);
}
}
Ein Problem bleibt bestehen: Wo sollten Sie das Kennwort speichern, mit dem Sie die Kennwörter verschlüsseln? Sie können es in der Quelldatei speichern und verschleiern, aber es ist nicht allzu schwer, es wieder zu finden. Alternativ können Sie es als Systemeigenschaft angeben, wenn Sie den Java-Prozess starten ( -DpropertyProtectionPassword=...
).
Das gleiche Problem bleibt bestehen, wenn Sie den KeyStore verwenden, der ebenfalls durch ein Kennwort geschützt ist. Grundsätzlich benötigen Sie irgendwo ein Hauptkennwort, und es ist ziemlich schwer zu schützen.
Ja, schreiben Sie definitiv keinen eigenen Algorithmus. Java hat viele Kryptographie-APIs.
Wenn das Betriebssystem, auf dem Sie installieren, über einen Keystore verfügt, können Sie damit Ihre Kryptoschlüssel speichern, die Sie zum Ver- und Entschlüsseln der vertraulichen Daten in Ihrer Konfiguration oder in anderen Dateien benötigen.
quelle
Schauen Sie sich jasypt an , eine Bibliothek, die mit minimalem Aufwand grundlegende Verschlüsselungsfunktionen bietet.
quelle
Ich denke, dass der beste Ansatz darin besteht, sicherzustellen, dass Ihre Konfigurationsdatei (die Ihr Passwort enthält) nur einem bestimmten Benutzerkonto zugänglich ist . Beispielsweise haben Sie möglicherweise einen anwendungsspezifischen Benutzer,
appuser
für den nur vertrauenswürdige Personen das Kennwort haben (und für den siesu
tun).Auf diese Weise entsteht kein lästiger Kryptografie-Overhead und Sie haben immer noch ein sicheres Passwort.
BEARBEITEN: Ich gehe davon aus, dass Sie Ihre Anwendungskonfiguration nicht außerhalb einer vertrauenswürdigen Umgebung exportieren (was angesichts der Frage nicht sicher ist, ob dies sinnvoll wäre).
quelle
Um die Probleme des Hauptkennworts zu lösen - der beste Ansatz besteht darin, das Kennwort nirgendwo zu speichern. Die Anwendung sollte Kennwörter für sich selbst verschlüsseln - damit nur sie entschlüsselt werden können. Wenn ich also eine .config-Datei verwenden würde, würde ich Folgendes tun : mySettings.config :
Also würde ich die Schlüssel einlesen, die in den encryptTheseKeys erwähnt sind, das Brodwalls-Beispiel von oben auf sie anwenden und sie mit einer Art Markierung (sagen wir Krypta :) in die Datei zurückschreiben , damit die Anwendung weiß, dass sie es nicht tut Auch hier würde die Ausgabe folgendermaßen aussehen:
Bewahren Sie die Originale an einem sicheren Ort auf ...
quelle
Der große Punkt und der Elefant im Raum und all das ist, dass, wenn Ihre Anwendung das Passwort erhalten kann, ein Hacker mit Zugriff auf die Box auch darauf zugreifen kann!
Die einzige Möglichkeit, dies zu umgehen, besteht darin, dass die Anwendung mithilfe der Standardeingabe auf der Konsole nach dem "Hauptkennwort" fragt und dieses dann zum Entschlüsseln der in der Datei gespeicherten Kennwörter verwendet. Dies macht es natürlich unmöglich, die Anwendung beim Booten unbeaufsichtigt zusammen mit dem Betriebssystem zu starten.
Selbst mit diesem Grad an Ärger könnte ein Hacker, wenn er Root-Zugriff erhält (oder sogar nur als Benutzer, der Ihre Anwendung ausführt), den Speicher entleeren und dort das Kennwort finden.
Die Sache, die sichergestellt werden muss, ist, nicht dem gesamten Unternehmen Zugriff auf den Produktionsserver (und damit auf die Passwörter) zu gewähren und sicherzustellen, dass es unmöglich ist, diese Box zu knacken!
quelle
Versuchen Sie es mit ESAPIs-Verschlüsselungsmethoden. Es ist einfach zu konfigurieren und Sie können auch Ihre Schlüssel leicht ändern.
http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encryptor.html
Du
1) verschlüsseln 2) entschlüsseln 3) signieren 4) nicht signieren 5) haschen 6) zeitbasierte Signaturen und vieles mehr mit nur einer Bibliothek.
quelle
Sehen Sie, was in Jetty zum Speichern von Kennwörtern (oder Hashes) in Konfigurationsdateien verfügbar ist, und prüfen Sie, ob die OBF-Codierung für Sie nützlich sein könnte. Dann sehen Sie in der Quelle, wie es gemacht wird.
http://www.eclipse.org/jetty/documentation/current/configuring-security-secure-passwords.html
quelle
Je nachdem, wie sicher Sie die Konfigurationsdateien benötigen oder wie zuverlässig Ihre Anwendung ist, ist http://activemq.apache.org/encrypted-passwords.html möglicherweise eine gute Lösung für Sie.
Wenn Sie keine Angst vor der Entschlüsselung des Kennworts haben und die Konfiguration mithilfe einer Bean zum Speichern des Kennwortschlüssels sehr einfach sein kann. Wenn Sie jedoch mehr Sicherheit benötigen, können Sie eine Umgebungsvariable mit dem Geheimnis festlegen und nach dem Start entfernen. Dabei müssen Sie sich Sorgen machen, dass die Anwendung / der Server ausfällt und die Anwendung nicht automatisch neu gestartet wird.
quelle
Wenn Sie Java 8 verwenden, kann die Verwendung des internen Base64-Codierers und -Decodierers durch Ersetzen vermieden werden
return new BASE64Encoder().encode(bytes);
mit
return Base64.getEncoder().encodeToString(bytes);
und
return new BASE64Decoder().decodeBuffer(property);
mit
return Base64.getDecoder().decode(property);
Beachten Sie, dass diese Lösung Ihre Daten nicht schützt, da die Methoden zum Entschlüsseln am selben Ort gespeichert sind. Es macht es nur schwieriger zu brechen. Hauptsächlich wird vermieden, es zu drucken und versehentlich allen zu zeigen.
quelle