Generieren Sie ein sicheres zufälliges Passwort in Java

Java Top

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs

1. Einleitung

In diesem Tutorial werden verschiedene Methoden vorgestellt, mit denen wir ein sicheres zufälliges Passwort in Java generieren können.

In unseren Beispielen werden Kennwörter mit zehn Zeichen generiert, die jeweils mindestens zwei Kleinbuchstaben, zwei Großbuchstaben, zwei Ziffern und zwei Sonderzeichen enthalten.

2. Passay verwenden

Passay ist eine Bibliothek zur Durchsetzung von Kennwortrichtlinien. Insbesondere können wir die Bibliothek verwenden, um das Kennwort mithilfe eines konfigurierbaren Regelsatzes zu generieren.

Mithilfe der Standardimplementierungen von CharacterData können wir die für das Kennwort erforderlichen Regeln formulieren. Darüber hinaus können wir benutzerdefinierte CharacterData- Implementierungen formulieren , die unseren Anforderungen entsprechen :

public String generatePassayPassword() { PasswordGenerator gen = new PasswordGenerator(); CharacterData lowerCaseChars = EnglishCharacterData.LowerCase; CharacterRule lowerCaseRule = new CharacterRule(lowerCaseChars); lowerCaseRule.setNumberOfCharacters(2); CharacterData upperCaseChars = EnglishCharacterData.UpperCase; CharacterRule upperCaseRule = new CharacterRule(upperCaseChars); upperCaseRule.setNumberOfCharacters(2); CharacterData digitChars = EnglishCharacterData.Digit; CharacterRule digitRule = new CharacterRule(digitChars); digitRule.setNumberOfCharacters(2); CharacterData specialChars = new CharacterData() { public String getErrorCode() { return ERROR_CODE; } public String getCharacters() { return "[email protected]#$%^&*()_+"; } }; CharacterRule splCharRule = new CharacterRule(specialChars); splCharRule.setNumberOfCharacters(2); String password = gen.generatePassword(10, splCharRule, lowerCaseRule, upperCaseRule, digitRule); return password; }

Hier haben wir eine benutzerdefinierte CharacterData- Implementierung für Sonderzeichen erstellt. Dies ermöglicht es uns, den Satz gültiger Zeichen einzuschränken.

Abgesehen davon verwenden wir Standardimplementierungen von CharacterData für unsere anderen Regeln.

Lassen Sie uns nun unseren Generator anhand eines Komponententests überprüfen. Zum Beispiel können wir das Vorhandensein von zwei Sonderzeichen überprüfen:

@Test public void whenPasswordGeneratedUsingPassay_thenSuccessful() { RandomPasswordGenerator passGen = new RandomPasswordGenerator(); String password = passGen.generatePassayPassword(); int specialCharCount = 0; for (char c : password.toCharArray()) if (c >= 33 

Es ist erwähnenswert, dass Passay zwar Open Source ist, jedoch sowohl unter LGPL als auch unter Apache 2 doppelt lizenziert ist . Wie bei jeder Software von Drittanbietern müssen wir sicherstellen, dass diese Lizenzen eingehalten werden, wenn wir sie in unseren Produkten verwenden. Auf der GNU-Website finden Sie weitere Informationen zu LGPL und Java.

3. Verwenden von RandomStringGenerator

Schauen wir uns als nächstes den RandomStringGenerator im Apache Commons-Text an. Mit RandomStringGenerator können wir Unicode-Zeichenfolgen generieren, die die angegebene Anzahl von Codepunkten enthalten.

Jetzt erstellen wir eine Instanz des Generators mithilfe der RandomStringGenerator.Builder- Klasse. Natürlich können wir auch die Eigenschaften des Generators weiter manipulieren.

Mit Hilfe des Builders können wir die Standardimplementierung der Zufälligkeit leicht ändern. Darüber hinaus können wir auch die Zeichen definieren, die in der Zeichenfolge zulässig sind:

public String generateRandomSpecialCharacters(int length) { RandomStringGenerator pwdGenerator = new RandomStringGenerator.Builder().withinRange(33, 45) .build(); return pwdGenerator.generate(length); } 

Eine Einschränkung bei der Verwendung von RandomStringGenerator besteht darin, dass die Anzahl der Zeichen in jedem Satz nicht angegeben werden kann, wie in Passay. Wir können dies jedoch umgehen, indem wir die Ergebnisse mehrerer Sätze zusammenführen:

public String generateCommonTextPassword() { String pwString = generateRandomSpecialCharacters(2).concat(generateRandomNumbers(2)) .concat(generateRandomAlphabet(2, true)) .concat(generateRandomAlphabet(2, false)) .concat(generateRandomCharacters(2)); List pwChars = pwString.chars() .mapToObj(data -> (char) data) .collect(Collectors.toList()); Collections.shuffle(pwChars); String password = pwChars.stream() .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString(); return password; }

Als nächstes überprüfen wir das generierte Passwort, indem wir die Kleinbuchstaben überprüfen:

@Test public void whenPasswordGeneratedUsingCommonsText_thenSuccessful() { RandomPasswordGenerator passGen = new RandomPasswordGenerator(); String password = passGen.generateCommonTextPassword(); int lowerCaseCount = 0; for (char c : password.toCharArray()) 

Standardmäßig RandomStringGenerator verwenden Marken ThreadLocalRandom für Beliebigkeit. Nun ist es wichtig zu erwähnen, dass dies keine kryptografische Sicherheit gewährleistet .

Wir können die Zufallsquelle jedoch mit random (TextRandomProvider) festlegen. Zum Beispiel können wir SecureTextRandomProvider für die kryptografische Sicherheit verwenden:

public String generateRandomSpecialCharacters(int length) { SecureTextRandomProvider stp = new SecureTextRandomProvider(); RandomStringGenerator pwdGenerator = new RandomStringGenerator.Builder() .withinRange(33, 45) .usingRandom(stp) .build(); return pwdGenerator.generate(length); }

4. Verwenden von RandomStringUtils

Eine weitere Option, die wir verwenden könnten, ist die RandomStringUtils- Klasse in der Apache Commons Lang Library. Diese Klasse stellt verschiedene statische Methoden zur Verfügung, die wir für unsere Problemstellung verwenden können.

Mal sehen, wie wir den Bereich von Codepunkten bereitstellen können, die für das Passwort akzeptabel sind:

 public String generateCommonLangPassword() { String upperCaseLetters = RandomStringUtils.random(2, 65, 90, true, true); String lowerCaseLetters = RandomStringUtils.random(2, 97, 122, true, true); String numbers = RandomStringUtils.randomNumeric(2); String specialChar = RandomStringUtils.random(2, 33, 47, false, false); String totalChars = RandomStringUtils.randomAlphanumeric(2); String combinedChars = upperCaseLetters.concat(lowerCaseLetters) .concat(numbers) .concat(specialChar) .concat(totalChars); List pwdChars = combinedChars.chars() .mapToObj(c -> (char) c) .collect(Collectors.toList()); Collections.shuffle(pwdChars); String password = pwdChars.stream() .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString(); return password; }

Um das generierte Passwort zu überprüfen, überprüfen wir die Anzahl der numerischen Zeichen:

@Test public void whenPasswordGeneratedUsingCommonsLang3_thenSuccessful() { RandomPasswordGenerator passGen = new RandomPasswordGenerator(); String password = passGen.generateCommonsLang3Password(); int numCount = 0; for (char c : password.toCharArray()) 

Hier RandomStringUtils Nutzt Zufallsstandardmäßig als Quelle der Zufälligkeit. Innerhalb der Bibliothek gibt es jedoch eine Methode, mit der wir die Quelle der Zufälligkeit angeben können:

String lowerCaseLetters = RandomStringUtils. random(2, 97, 122, true, true, null, new SecureRandom());

Jetzt können wir die kryptografische Sicherheit mithilfe einer Instanz von SecureRandom gewährleisten . Diese Funktionalität kann jedoch nicht auf andere Methoden in der Bibliothek erweitert werden. Nebenbei bemerkt befürwortet Apache die Verwendung von RandomStringUtils nur für einfache Anwendungsfälle.

5. Verwenden einer benutzerdefinierten Dienstprogrammmethode

Wir können auch die SecureRandom- Klasse verwenden, um eine benutzerdefinierte Dienstprogrammklasse für unser Szenario zu erstellen. Lassen Sie uns zunächst eine Zeichenfolge mit Sonderzeichen der Länge zwei generieren:

public Stream getRandomSpecialChars(int count) { Random random = new SecureRandom(); IntStream specialChars = random.ints(count, 33, 45); return specialChars.mapToObj(data -> (char) data); }

Beachten Sie auch, dass 33 und 45 den Bereich der Unicode-Zeichen bezeichnen. Jetzt können wir gemäß unseren Anforderungen mehrere Streams generieren. Dann können wir die Ergebnismengen zusammenführen, um das erforderliche Passwort zu generieren:

public String generateSecureRandomPassword() { Stream pwdStream = Stream.concat(getRandomNumbers(2), Stream.concat(getRandomSpecialChars(2), Stream.concat(getRandomAlphabets(2, true), getRandomAlphabets(4, false)))); List charList = pwdStream.collect(Collectors.toList()); Collections.shuffle(charList); String password = charList.stream() .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) .toString(); return password; } 

Lassen Sie uns nun das generierte Passwort für die Anzahl der Sonderzeichen überprüfen:

@Test public void whenPasswordGeneratedUsingSecureRandom_thenSuccessful() { RandomPasswordGenerator passGen = new RandomPasswordGenerator(); String password = passGen.generateSecureRandomPassword(); int specialCharCount = 0; for (char c : password.toCharArray()) c = 2); 

6. Fazit

In diesem Tutorial konnten wir mithilfe verschiedener Bibliotheken Passwörter generieren, die unseren Anforderungen entsprechen.

Wie immer sind die im Artikel verwendeten Codebeispiele auf GitHub verfügbar.

Java unten

Ich habe gerade den neuen Learn Spring- Kurs angekündigt , der sich auf die Grundlagen von Spring 5 und Spring Boot 2 konzentriert:

>> Überprüfen Sie den Kurs