Wichtige Notiz:
Wenn Sie das Authentifizierungssystem als Ganzes entwerfen, sollten Sie keine Kennwörter speichern, auch wenn diese verschlüsselt sind. Sie speichern einen Hash und prüfen, ob die bei der Anmeldung angegebenen Kennwörter mit demselben Hash übereinstimmen. Auf diese Weise wird durch eine Sicherheitsverletzung in Ihrer Datenbank vermieden, dass die Kennwörter Ihrer Benutzer offengelegt werden.
Nach alledem, mit einer inneren zu äußeren Denkweise, sind hier einige Schritte, um Ihren Prozess zu schützen:
Im ersten Schritt sollten Sie Ihre Passwortbehandlung von String
auf ändern character array
.
Der Grund dafür ist, dass a String
ein immutable
Objekt ist und seine Daten daher nicht sofort bereinigt werden, selbst wenn das Objekt auf gesetzt ist null
. Die Daten werden stattdessen für die Speicherbereinigung festgelegt. Dies führt zu Sicherheitsproblemen, da böswillige Programme möglicherweise vor der Bereinigung Zugriff auf diese String
(Kennwort-) Daten erhalten.
Dies ist der Hauptgrund, warum die JPasswordField-getText()
Methode von Swing veraltet ist und warum getPassword()
Zeichenarrays verwendet werden .
Der zweite Schritt besteht darin, Ihre Anmeldeinformationen zu verschlüsseln und sie während des Authentifizierungsprozesses nur vorübergehend zu entschlüsseln. Oder um sie serverseitig zu hashen, speichern Sie diesen Hash und "vergessen" Sie das ursprüngliche Passwort.
Dies stellt ähnlich wie im ersten Schritt sicher, dass Ihre Schwachstellenzeit so kurz wie möglich ist.
Es wird empfohlen, dass Ihre Anmeldeinformationen nicht fest codiert sind und dass Sie sie stattdessen zentral, konfigurierbar und leicht zu warten speichern, z. B. als Konfigurations- oder Eigenschaftendatei oder als Datenbank.
Sie sollten Ihre Anmeldeinformationen verschlüsseln, bevor Sie die Datei speichern. Außerdem können Sie eine zweite Verschlüsselung auf die Datei selbst anwenden (2-Schicht-Verschlüsselung für die Anmeldeinformationen und 1-Schicht für andere Dateiinhalte).
Beachten Sie, dass jeder der beiden oben genannten Verschlüsselungsprozesse selbst mehrschichtig sein kann. Jede Verschlüsselung kann eine individuelle Anwendung des Triple Data Encryption Standard (AKA TDES und 3DES) als konzeptionelles Beispiel sein.
Nachdem Ihre lokale Umgebung ordnungsgemäß geschützt wurde (aber denken Sie daran, dass sie niemals "sicher" ist!), Wendet der dritte Schritt einen grundlegenden Schutz auf Ihren Übertragungsprozess an, indem Sie TLS (Transport Layer Security) oder SSL (Secure Sockets Layer) verwenden .
Der vierte Schritt besteht darin, andere Schutzmethoden anzuwenden.
Wenden Sie beispielsweise Verschleierungstechniken auf Ihre "zu verwendende" Kompilierung an, um (wenn auch in Kürze) zu vermeiden, dass Ihre Sicherheitsmaßnahmen offengelegt werden, falls Ihr Programm von Frau Eve, Herrn Mallory oder einer anderen Person (dem Bad-) erhalten wird. Jungs) und dekompiliert.
UPDATE 1:
Auf Anfrage von @ Damien.Bell finden Sie hier ein Beispiel, das den ersten und zweiten Schritt abdeckt:
private static final Map<String, String> COMMON_ATTRIBUTES = new HashMap<String, String>();
private static final Map<String, char[]> SECURE_ATTRIBUTES = new HashMap<String, char[]>();
private static final char[] PASSWORD = "Unauthorized_Personel_Is_Unauthorized".toCharArray();
private static final byte[] SALT = {
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,
(byte) 0xde, (byte) 0x33, (byte) 0x10, (byte) 0x12,};
private static final File DESKTOP = new File(System.getProperty("user.home") + "/Desktop");
private static final String NO_ENCRYPTION = "no_layers.txt";
private static final String SINGLE_LAYER = "single_layer.txt";
private static final String DOUBLE_LAYER = "double_layer.txt";
public static void main(String[] args) throws GeneralSecurityException, FileNotFoundException, IOException {
COMMON_ATTRIBUTES.put("Gender", "Male");
COMMON_ATTRIBUTES.put("Age", "21");
COMMON_ATTRIBUTES.put("Name", "Hypot Hetical");
COMMON_ATTRIBUTES.put("Nickname", "HH");
SECURE_ATTRIBUTES.put("Username", "Hypothetical".toCharArray());
SECURE_ATTRIBUTES.put("Password", "LetMePass_Word".toCharArray());
create_EncryptedFile(NO_ENCRYPTION, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 0);
create_EncryptedFile(SINGLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 1);
create_EncryptedFile(DOUBLE_LAYER, COMMON_ATTRIBUTES, SECURE_ATTRIBUTES, 2);
System.out.println("NO ENCRYPTION: \n" + readFile_NoDecryption(NO_ENCRYPTION) + "\n\n\n");
System.out.println("SINGLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(SINGLE_LAYER) + "\n\n\n");
System.out.println("DOUBLE LAYER ENCRYPTION: \n" + readFile_NoDecryption(DOUBLE_LAYER) + "\n\n\n");
String decryptedContent = readFile_ApplyDecryption(DOUBLE_LAYER);
System.out.println("READ: [first layer decrypted]\n" + decryptedContent + "\n\n\n");
for (String line : decryptedContent.split("\n")) {
String[] pair = line.split(": ", 2);
if (pair[0].equalsIgnoreCase("Username") || pair[0].equalsIgnoreCase("Password")) {
System.out.println("Decrypted: " + pair[0] + ": " + decrypt(pair[1]));
}
}
}
private static String encrypt(byte[] property) throws GeneralSecurityException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.ENCRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
String encrypted = Base64.encodeBytes(pbeCipher.doFinal(property));
for (int i = 0; i < property.length; i++) {
property[i] = 0;
}
property = null;
System.gc();
return encrypted;
}
private static String encrypt(char[] property) throws GeneralSecurityException {
byte[] bytes = new byte[property.length];
for (int i = 0; i < property.length; i++) {
bytes[i] = (byte) property[i];
}
String encrypted = encrypt(bytes);
return encrypted;
}
private static String encrypt(String property) throws GeneralSecurityException {
String encrypted = encrypt(property.getBytes());
property = null;
return encrypted;
}
private static String decrypt(String property) throws GeneralSecurityException, IOException {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD));
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
pbeCipher.init(Cipher.DECRYPT_MODE, key, new PBEParameterSpec(SALT, 20));
return new String(pbeCipher.doFinal(Base64.decode(property)));
}
private static void create_EncryptedFile(
String fileName,
Map<String, String> commonAttributes,
Map<String, char[]> secureAttributes,
int layers)
throws GeneralSecurityException, FileNotFoundException, IOException {
StringBuilder sb = new StringBuilder();
for (String k : commonAttributes.keySet()) {
sb.append(k).append(": ").append(commonAttributes.get(k)).append(System.lineSeparator());
}
for (String k : secureAttributes.keySet()) {
String encryptedValue;
if (layers >= 1) {
encryptedValue = encrypt(secureAttributes.get(k));
} else {
encryptedValue = new String(secureAttributes.get(k));
}
sb.append(k).append(": ").append(encryptedValue).append(System.lineSeparator());
}
File f = new File(DESKTOP, fileName);
if (!f.getParentFile().exists()) {
f.getParentFile().mkdirs();
} else if (f.exists()) {
f.delete();
}
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
if (layers >= 2) {
bw.append(encrypt(sb.toString().trim()));
} else {
bw.append(sb.toString().trim());
}
bw.flush();
bw.close();
}
private static String readFile_NoDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return sb.toString();
}
private static String readFile_ApplyDecryption(String fileName) throws FileNotFoundException, IOException, GeneralSecurityException {
File f = new File(DESKTOP, fileName);
BufferedReader br = new BufferedReader(new FileReader(f));
StringBuilder sb = new StringBuilder();
while (br.ready()) {
sb.append(br.readLine()).append(System.lineSeparator());
}
return decrypt(sb.toString());
}
Ein vollständiges Beispiel, das sich mit jedem Schutzschritt befasst, würde weit über das hinausgehen, was ich für diese Frage für angemessen halte, da es um "Was sind die Schritte" und nicht um "Wie man sie anwendet" geht .
Es würde meine Antwort (endlich die Stichprobe) weit überbewerten, während andere Fragen hier auf SO bereits auf das "Wie" dieser Schritte gerichtet sind, weitaus angemessener sind und eine weitaus bessere Erklärung und Stichprobe für die Implementierung von bieten jeder einzelne Schritt.