Guide de Passay
1. introduction
De nos jours, la plupart des applications Web ont leur stratégie de mot de passe, qui est simplement créée pour obliger les utilisateurs à créer des mots de passe difficiles à déchirer.
Pour générer de tels mots de passe ou les valider, nous pouvons utiliserPassay library.
2. Dépendance Maven
Si nous voulons utiliser la bibliothèque Passay dans notre projet, il est nécessaire d'ajouter la dépendance suivante à nospom.xml:
org.passay
passay
1.3.1
On peut le trouverhere.
3. Validation du mot de passe
La validation de mot de passe est l'une des deux fonctionnalités principales fournies par la bibliothèque Passay. C'est simple et intuitif. Découvrons-le.
3.1. PasswordData
Pour valider notre mot de passe, nous devrions utiliserPasswordData.It’s a container for information that is necessary for validation. Il peut stocker des données telles que:
-
mot de passe
-
Nom d'utilisateur
-
liste des références de mot de passe
-
origine
Les propriétés de mot de passe et nom d'utilisateur s'expliquent. La bibliothèque Passay nous donneHistoricalReference etSourceReference que nous pouvons ajouter à la liste des références de mot de passe.
Nous pouvons utiliser le champ d'origine pour contenir des informations indiquant si le mot de passe a été généré ou défini par un utilisateur.
3.2. PasswordValidator
We should know that we need PasswordData and PasswordValidator objects to start validating passwords. Nous avons déjà discuté dePasswordData. Créons maintenantPasswordValidator.
Premièrement, nous devrions définir un ensemble de règles pour la validation du mot de passe. Nous devons les transmettre au constructeur lors de la création d'un objetPasswordValidator:
PasswordValidator passwordValidator = new PasswordValidator(new LengthRule(5));
Il existe deux manières de transmettre notre mot de passe à un objetPasswordData. Nous le transmettons soit au constructeur, soit à la méthode setter:
PasswordData passwordData = new PasswordData("1234");
PasswordData passwordData2 = new PasswordData();
passwordData.setPassword("1234");
Nous pouvons valider notre mot de passe en appelant la méthodevalidate() surPasswordValidator:
RuleResult validate = passwordValidator.validate(passwordData);
En conséquence, nous obtiendrons un objetRuleResult.
3.3. RuleResult
RuleResult contient des informations intéressantes sur un processus de validation. Il résulte de la méthodevalidate().
Tout d'abord, il peut nous dire si le mot de passe est valide:
Assert.assertEquals(false, validate.isValid());
Moreover, we can learn what errors are returned when the password is invalid. Les codes d'erreur et les descriptions de validation sont conservés dansRuleResultDetail:
RuleResultDetail ruleResultDetail = validate.getDetails().get(0);
Assert.assertEquals("TOO_SHORT", ruleResultDetail.getErrorCode());
Assert.assertEquals(5, ruleResultDetail.getParameters().get("minimumLength"));
Assert.assertEquals(5, ruleResultDetail.getParameters().get("maximumLength"));
Enfin, nous pouvons explorer les métadonnées de la validation du mot de passe avecRuleResultMetadata:
Integer lengthCount = validate
.getMetadata()
.getCounts()
.get(RuleResultMetadata.CountCategory.Length);
Assert.assertEquals(Integer.valueOf(4), lengthCount);
4. Génération de mot de passe
En plus de la validation, la bibliothèquePassay nous permet de générer des mots de passe. We can provide rules which the generator should use.
Pour générer un mot de passe, nous avons besoin d'un objetPasswordGenerator. Une fois que nous l'avons, nous appelons la méthodegeneratePassword() et passons la liste deCharacterRules. Voici un exemple de code:
CharacterRule digits = new CharacterRule(EnglishCharacterData.Digit);
PasswordGenerator passwordGenerator = new PasswordGenerator();
String password = passwordGenerator.generatePassword(10, digits);
Assert.assertTrue(password.length() == 10);
Assert.assertTrue(containsOnlyCharactersFromSet(password, "0123456789"));
Nous devons savoir que nous avons besoin d'un objet deCharacterData pour créerCharacterRule. Another interesting fact is that the library provides us with EnglishCharacterData. C'est une énumération de cinq jeux de caractères:
-
chiffres
-
alphabet anglais minuscule
-
alphabet anglais majuscule
-
combinaison de jeux minuscules et majuscules
-
caractères spéciaux
However, nothing can stop us from defining our set of characters. C'est aussi simple que d'implémenter l'interfaceCharacterData. Voyons comment nous pouvons le faire:
CharacterRule specialCharacterRule = new CharacterRule(new CharacterData() {
@Override
public String getErrorCode() {
return "SAMPLE_ERROR_CODE";
}
@Override
public String getCharacters() {
return "[email protected]#";
}
});
PasswordGenerator passwordGenerator = new PasswordGenerator();
String password = passwordGenerator.generatePassword(10, specialCharacterRule);
Assert.assertTrue(containsOnlyCharactersFromSet(password, "[email protected]#"));
5. Règles de correspondance positives
Nous avons déjà appris comment générer et valider des mots de passe. Pour ce faire, nous devons définir un ensemble de règles. For that reason, we should know that there are two types of rules available in Passay: positive matching rules and negative matching rules.
Tout d'abord, voyons quelles sont les règles positives et comment nous pouvons les utiliser.
Les règles de correspondance positive acceptent les mots de passe contenant les caractères fournis, les expressions régulières ou s'inscrivant dans certaines limitations.
Il y a six règles de correspondance positives:
-
AllowedCharacterRule - définit tous les caractères que le mot de passe doit inclure
-
AllowedRegexRule - définit une expression régulière à laquelle le mot de passe doit correspondre
-
CharacterRule - définit un jeu de caractères et un nombre minimal de caractères à inclure dans le mot de passe
-
LengthRule - définit une longueur minimale du mot de passe
-
CharacterCharacteristicsRule - vérifie si le mot de passe remplitN des règles définies.
-
LengthComplexityRule - nous permet de définir différentes règles pour différentes longueurs de mot de passe
5.1. Règles simples de correspondance positive
Maintenant, nous allons couvrir toutes les règles qui ont une configuration simple. They define a set of legal characters or patterns or an acceptable password’s length.
Voici un court exemple des règles discutées:
PasswordValidator passwordValidator = new PasswordValidator(
new AllowedCharacterRule(new char[] { 'a', 'b', 'c' }),
new CharacterRule(EnglishCharacterData.LowerCase, 5),
new LengthRule(8, 10)
);
RuleResult validate = passwordValidator.validate(new PasswordData("12abc"));
assertFalse(validate.isValid());
assertEquals(
"ALLOWED_CHAR:{illegalCharacter=1, matchBehavior=contains}",
getDetail(validate, 0));
assertEquals(
"ALLOWED_CHAR:{illegalCharacter=2, matchBehavior=contains}",
getDetail(validate, 1));
assertEquals(
"TOO_SHORT:{minimumLength=8, maximumLength=10}",
getDetail(validate, 4));
We can see that each rule gives us a clear explanation if the password is not valid. Il y a des notifications indiquant que le mot de passe est trop court et contient deux caractères non autorisés. Nous pouvons également remarquer que le mot de passe ne correspond pas à l'expression régulière fournie.
De plus, nous sommes informés qu’il ne contient pas suffisamment de lettres minuscules.
5.2. CharacterCharacterisitcsRule
CharcterCharacterisitcsRule est plus complexe que les règles présentées auparavant. To create a CharcterCharacterisitcsRule object, we need to provide a list of CharacterRules. De plus, nous devons définir le nombre d’entre eux que le mot de passe doit correspondre. Nous pouvons le faire de cette façon:
CharacterCharacteristicsRule characterCharacteristicsRule = new CharacterCharacteristicsRule(
3,
new CharacterRule(EnglishCharacterData.LowerCase, 5),
new CharacterRule(EnglishCharacterData.UpperCase, 5),
new CharacterRule(EnglishCharacterData.Digit),
new CharacterRule(EnglishCharacterData.Special)
);
PrésentéCharacterCharacteristicsRule nécessite un mot de passe contenant trois des quatre règles fournies.
5.3. LengthComplexityRule
D'un autre côté, la bibliothèquePassay nous fournitLengthComplexityRule. It allows us to define which rules should be applied to the password of which length. Contrairement àCharacterCharacteristicsRule, ils nous permettent d'utiliser toutes sortes de règles - pas seulementCharacterRule.
Analysons l'exemple:
LengthComplexityRule lengthComplexityRule = new LengthComplexityRule();
lengthComplexityRule.addRules("[1,5]", new CharacterRule(EnglishCharacterData.LowerCase, 5));
lengthComplexityRule.addRules("[6,10]",
new AllowedCharacterRule(new char[] { 'a', 'b', 'c', 'd' }));
Comme nous pouvons le voir pour un mot de passe de un à cinq caractères, nous appliquonsCharacterRule. Mais pour un mot de passe contenant six à dix caractères, nous voulons que le mot de passe corresponde àAllowedCharacterRule.
6. Règles de correspondance négatives
Contrairement aux règles de correspondance positive, les règles de correspondance négative rejettent les mots de passe contenant des caractères fournis, des expressions régulières, des entrées, etc.
Voyons quelles sont les règles de correspondance négatives:
-
IllegalCharacterRule - définit tous les caractères qu'un mot de passe ne doit pas contenir
-
IllegalRegexRule - définit une expression régulière qui ne doit pas correspondre
-
IllegalSequenceRule - vérifie si un mot de passe a une séquence de caractères illégale
-
NumberRangeRule - définit une plage de nombres qu'un mot de passe ne doit pas contenir
-
WhitespaceRule - vérifie si un mot de passe contient des espaces
-
DictionaryRule - vérifie si un mot de passe est égal à un enregistrement de dictionnaire
-
DictionarySubstringRule - vérifie si un mot de passe contient un enregistrement de dictionnaire
-
HistoryRule - vérifie si un mot de passe contient une référence de mot de passe historique
-
DigestHistoryRule - vérifie si un mot de passe contient une référence de mot de passe historique digérée
-
SourceRule - vérifie si un mot de passe contient une référence de mot de passe source
-
DigestSourceRule - vérifie si un mot de passe contient une référence de mot de passe de source de résumé
-
UsernameRule - vérifie si un mot de passe contient un nom d'utilisateur
-
RepeatCharacterRegexRule - vérifie si un mot de passe contient des caractèresASCII répétés
6.1. Règles de correspondance négatives simples
Tout d'abord, nous allons voir comment nous pouvons utiliser des règles simples telles queIllegalCharacterRule,IllegalRegexRule, etc. Voici un court exemple:
PasswordValidator passwordValidator = new PasswordValidator(
new IllegalCharacterRule(new char[] { 'a' }),
new NumberRangeRule(1, 10),
new WhitespaceRule()
);
RuleResult validate = passwordValidator.validate(new PasswordData("abcd22 "));
assertFalse(validate.isValid());
assertEquals(
"ILLEGAL_CHAR:{illegalCharacter=a, matchBehavior=contains}",
getDetail(validate, 0));
assertEquals(
"ILLEGAL_NUMBER_RANGE:{number=2, matchBehavior=contains}",
getDetail(validate, 4));
assertEquals(
"ILLEGAL_WHITESPACE:{whitespaceCharacter= , matchBehavior=contains}",
getDetail(validate, 5));
L'exemple nous montre comment fonctionnent les règles décrites. De la même manière que les règles de correspondance positives, elles nous donnent un retour complet sur la validation.
6.2. Règles du dictionnaire
Que faire si nous voulons vérifier si un mot de passe n'est pas égal aux mots fournis.
Pour cette raison, la bibliothèquePassay nous donne d'excellents outils pour cela. DécouvronsDictionaryRule etDictionarySubstringRule:
WordListDictionary wordListDictionary = new WordListDictionary(
new ArrayWordList(new String[] { "bar", "foobar" }));
DictionaryRule dictionaryRule = new DictionaryRule(wordListDictionary);
DictionarySubstringRule dictionarySubstringRule = new DictionarySubstringRule(wordListDictionary);
We can see dictionary rules enable us to provide a list of banned words. Il est avantageux d'avoir une liste des mots de passe les plus courants ou les plus faciles à casser. Par conséquent, il est raisonnable d’interdire aux utilisateurs de les utiliser.
Dans la vie réelle, nous chargerions certainement une liste de mots à partir d'un fichier texte ou d'une base de données. Dans ce cas, nous pouvons utiliserWordLists. Il a trois méthodes surchargées qui prennent un tableau deReaders et créentArrayWordList.
6.3. HistoryRule etSourceRule
De plus, la librairiePassay nous donneHistoryRule etSourceRule. Ils peuvent valider les mots de passe par rapport aux mots de passe historiques ou au contenu textuel de différentes sources.
Jetons un œil à l'exemple:
SourceRule sourceRule = new SourceRule();
HistoryRule historyRule = new HistoryRule();
PasswordData passwordData = new PasswordData("123");
passwordData.setPasswordReferences(
new PasswordData.SourceReference("source", "password"),
new PasswordData.HistoricalReference("12345")
);
PasswordValidator passwordValidator = new PasswordValidator(
historyRule, sourceRule);
HistoryRules nous aide à vérifier si un mot de passe a déjà été utilisé. Étant donné que ces pratiques ne sont pas sécurisées, nous ne voulons pas que les utilisateurs utilisent d'anciens mots de passe.
Par contre,SourceRule nous permet de vérifier si le mot de passe est différent de ceux fournis dansSourceReferences. Nous pouvons éviter le risque d'avoir les mêmes mots de passe dans différents systèmes ou applications.
Il est à noter qu’il existe des règles telles queDigestSourceRule etDigestHistoryRule.. Nous les aborderons dans le paragraphe suivant.
6.4. Règles de résumé
Il existe deux règles de résumé dans la bibliothèquePassay:DigestHistoryRule etDigestSourceRule. Digest rules are intended to work with passwords stored as digest or hash. Par conséquent, pour les définir, nous devons fournir un objetEncodingHashBean.
Voyons comment cela se passe:
List historicalReferences = Arrays.asList(
new PasswordData.HistoricalReference(
"SHA256",
"2e4551de804e27aacf20f9df5be3e8cd384ed64488b21ab079fb58e8c90068ab"
));
EncodingHashBean encodingHashBean = new EncodingHashBean(
new CodecSpec("Base64"),
new DigestSpec("SHA256"),
1,
false
);
Cette fois, nous créonsHistoricalReference par une étiquette et le mot de passe encodé au constructeur. Après cela, nous avons instanciéEncodingHashBean avec le codec et l'algorithme de résumé appropriés.
De plus, nous pouvons spécifier le nombre d'itérations et si l'algorithme est salé.
Une fois que nous avons un haricot d’encodage, nous pouvons valider notre mot de passe digest:
PasswordData passwordData = new PasswordData("example!");
passwordData.setPasswordReferences(historicalReferences);
PasswordValidator passwordValidator = new PasswordValidator(new DigestHistoryRule(encodingHashBean));
RuleResult validate = passwordValidator.validate(passwordData);
Assert.assertTrue(validate.isValid());
Nous pouvons en savoir plus surEncodingHashinBean àCryptacular library webpage.
6.5. RepeatCharacterRegexRule
Une autre règle de validation intéressante estRepeatCharacterRegexRule. We can use it to check whether password contains repeating ASCII characters.
Voici un exemple de code:
PasswordValidator passwordValidator = new PasswordValidator(new RepeatCharacterRegexRule(3));
RuleResult validate = passwordValidator.validate(new PasswordData("aaabbb"));
assertFalse(validate.isValid());
assertEquals("ILLEGAL_MATCH:{match=aaa, pattern=([^\\x00-\\x1F])\\1{2}}", getDetail(validate, 0));
6.6. UsernameRule
La dernière règle que nous allons aborder dans ce chapitre estUsernameRule. It enables us to prohibit using the user’s name in the password.
Comme nous l’avons appris auparavant, nous devons stocker le nom d’utilisateur dansPasswordData:
PasswordValidator passwordValidator = new PasswordValidator(new UsernameRule());
PasswordData passwordData = new PasswordData("testuser1234");
passwordData.setUsername("testuser");
RuleResult validate = passwordValidator.validate(passwordData);
assertFalse(validate.isValid());
assertEquals("ILLEGAL_USERNAME:{username=testuser, matchBehavior=contains}", getDetail(validate, 0));
7. Messages personnalisés
La bibliothèquePassay nous permet de personnaliser les messages renvoyés par les règles de validation. Firstly, we should define the messages and assign them to error codes.
Nous pouvons les mettre dans un fichier simple. Voyons à quel point c'est facile:
TOO_LONG=Password must not have more characters than %2$s.
TOO_SHORT=Password must not contain less characters than %2$s.
Une fois que nous avons des messages, nous devons charger ce fichier. Enfin, nous pouvons le passer dans l'objetPasswordValidator.
Voici un exemple de code:
URL resource = this.getClass().getClassLoader().getResource("messages.properties");
Properties props = new Properties();
props.load(new FileInputStream(resource.getPath()));
MessageResolver resolver = new PropertiesMessageResolver(props);
Comme nous pouvons le voir, nous avons chargé le fichiermessage.properties et l'avons passé dans l'objetProperties. Ensuite, nous pouvons utiliser l'objetProperties pour créer desPropertiesMessageResolver.
Jetons un coup d'œil à l'exemple d'utilisation du résolveur de messages:
PasswordValidator validator = new PasswordValidator(
resolver,
new LengthRule(8, 16),
new WhitespaceRule()
);
RuleResult tooShort = validator.validate(new PasswordData("XXXX"));
RuleResult tooLong = validator.validate(new PasswordData("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"));
Assert.assertEquals(
"Password must not contain less characters than 16.",
validator.getMessages(tooShort).get(0));
Assert.assertEquals(
"Password must not have more characters than 16.",
validator.getMessages(tooLong).get(0));
L'exemple montre clairement que nous pouvons traduire tous les codes d'erreur avec le validateur équipé d'un résolveur de messages.
8. Conclusion
Dans ce didacticiel, nous avons appris à utiliser la bibliothèquePassay. Nous avons analysé plusieurs exemples d'utilisation facile de la bibliothèque pour la validation de mot de passe. Les règles fournies couvrent la plupart des méthodes courantes permettant de garantir la sécurité d'un mot de passe.
Mais nous devons nous rappeler que la bibliothèque Passay elle-même ne sécurise pas notre mot de passe. Premièrement, nous devrions apprendre quelles sont les règles générales et utiliser ensuite la bibliothèque pour les implémenter.
Tous les exemples, comme toujours, peuvent être trouvésover on GitHub.