Hasilkan Kata Laluan Rawak Selamat di Java

Java Teratas

Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:

>> SEMAK KURSUS

1. Pengenalan

Dalam tutorial ini, kita akan melihat pelbagai kaedah yang dapat kita gunakan untuk menghasilkan kata laluan rawak yang selamat di Java.

Dalam contoh kami, kami akan menghasilkan kata laluan sepuluh aksara, masing-masing dengan minimum dua aksara kecil, dua aksara besar, dua digit, dan dua watak khas.

2. Menggunakan Passay

Passay adalah perpustakaan penguatkuasaan dasar kata laluan. Terutama, kita dapat memanfaatkan perpustakaan untuk menghasilkan kata laluan menggunakan set peraturan yang boleh dikonfigurasi.

Dengan bantuan pelaksanaan CharacterData lalai , kita dapat merumuskan peraturan yang diperlukan untuk kata laluan. Selanjutnya, kami dapat merumuskan implementasi CharacterData khusus untuk memenuhi keperluan kami :

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; }

Di sini, kami telah membuat pelaksanaan CharacterData khusus untuk watak khas. Ini membolehkan kita menyekat set aksara sah yang dibenarkan.

Selain itu, kami menggunakan implementasi lalai dari CharacterData untuk peraturan kami yang lain.

Sekarang, mari periksa penjana kami terhadap ujian unit. Sebagai contoh, kita dapat memeriksa kehadiran dua watak khas:

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

Perlu diperhatikan bahawa walaupun Passay adalah sumber terbuka, ia dilesenkan dua di bawah LGPL dan Apache 2 . Seperti mana-mana perisian pihak ketiga, kita mesti mematuhi lesen ini semasa kita menggunakannya dalam produk kita. Laman web GNU mempunyai lebih banyak maklumat mengenai LGPL dan Java.

3. Menggunakan RandomStringGenerator

Seterusnya, mari kita lihat RandomStringGenerator dalam Teks Apache Commons. Dengan RandomStringGenerator, kita dapat menghasilkan rentetan Unicode yang mengandungi bilangan titik kod yang ditentukan.

Sekarang, kita akan membuat contoh penjana dengan menggunakan kelas RandomStringGenerator.Builder . Sudah tentu, kita juga dapat memanipulasi sifat penjana.

Dengan bantuan pembangun, kita dapat dengan mudah mengubah pelaksanaan rawak secara lalai. Selain itu, kita juga dapat menentukan watak yang dibenarkan dalam rentetan:

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

Sekarang, satu batasan penggunaan RandomStringGenerator adalah bahawa ia tidak memiliki kemampuan untuk menentukan jumlah karakter dalam setiap set, seperti di Passay. Namun, kita dapat mengelakkannya dengan menggabungkan hasil beberapa set:

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; }

Seterusnya, mari kita mengesahkan kata laluan yang dihasilkan dengan mengesahkan huruf kecil:

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

Secara lalai, RandomStringGenerator menggunakan ThreadLocalRandom untuk rawak. Sekarang, penting untuk disebutkan bahawa ini tidak memastikan keselamatan kriptografi .

Namun, kita dapat menetapkan sumber keacakan menggunakan usingRandom (TextRandomProvider). Sebagai contoh, kita dapat menggunakan SecureTextRandomProvider untuk keselamatan kriptografi:

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. Menggunakan RandomStringUtils

Pilihan lain yang dapat kita gunakan adalah kelas RandomStringUtils di Perpustakaan Apache Commons Lang. Kelas ini mendedahkan beberapa kaedah statik yang boleh kita gunakan untuk penyataan masalah kita.

Mari lihat bagaimana kita dapat memberikan pelbagai titik kod yang boleh diterima untuk kata laluan:

 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; }

Untuk mengesahkan kata laluan yang dihasilkan, mari kita sahkan bilangan aksara angka:

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

Here, RandomStringUtils makes use of Random by default as the source of randomness. However, there is a method within the library that lets us specify the source of randomness:

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

Now, we could ensure cryptographic security using an instance of SecureRandom. However, this functionality cannot be extended to other methods in the library. On a side note, Apache advocates the usage of RandomStringUtils for simple use cases only.

5. Using a Custom Utility Method

We can also make use of the SecureRandom class to create a custom utility class for our scenario. For starters, let's generate a string of special characters of length two:

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

Also, notice that 33 and 45 denote the range of Unicode characters. Now, we can generate multiple streams as per our requirements. Then we can merge the result sets to generate the required password:

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; } 

Now, let's validate the generated password for the number of special characters:

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

6. Conclusion

In this tutorial, we were able to generate passwords, conforming to our requirements, using different libraries.

As always, the code samples used in the article are available over on GitHub.

Java bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE