Путеводитель по Пассею

Путеводитель по Пассаю

1. Вступление

В настоящее время большинство веб-приложений имеют свою политику паролей, которая, проще говоря, создана, чтобы заставить пользователей создавать пароли, которые трудно взломать.

Чтобы сгенерировать такие пароли или проверить их, мы можем использоватьPassay library.

2. Maven Dependency

Если мы хотим использовать библиотеку Passay в нашем проекте, необходимо добавить следующую зависимость к нашемуpom.xml:


    org.passay
    passay
    1.3.1

Мы можем найти егоhere.

3. Проверка пароля

Проверка пароля является одной из двух основных функций, предоставляемых библиотекой Passay. Это легко и интуитивно понятно. Давай узнаем это.

3.1. PasswordDataс

Чтобы проверить наш пароль, мы должны использоватьPasswordData.It’s a container for information that is necessary for validation.. Он может хранить такие данные, как:

  • пароль

  • имя пользователя

  • список ссылок на пароли

  • происхождения

Свойства пароля и имени пользователя объясняются сами собой. Библиотека Passay дает намHistoricalReference иSourceReference, которые мы можем добавить в список ссылок на пароли.

Мы можем использовать поле источника для хранения информации о том, был ли пароль сгенерирован или определен пользователем.

3.2. PasswordValidatorс

We should know that we need PasswordData and PasswordValidator objects to start validating passwords. Мы уже обсуждалиPasswordData. Теперь создадимPasswordValidator.

Во-первых, мы должны определить набор правил для проверки пароля. Мы должны передать их конструктору при создании объектаPasswordValidator:

PasswordValidator passwordValidator = new PasswordValidator(new LengthRule(5));

Есть два способа передать наш пароль объектуPasswordData. Мы передаем его либо в конструктор, либо в метод setter:

PasswordData passwordData = new PasswordData("1234");

PasswordData passwordData2 = new PasswordData();
passwordData.setPassword("1234");

Мы можем проверить наш пароль, вызвав методvalidate() наPasswordValidator:

RuleResult validate = passwordValidator.validate(passwordData);

В результате мы получим объектRuleResult.

3.3. RuleResultс

RuleResult содержит интересную информацию о процессе проверки. Это результат методаvalidate().

Прежде всего, он может сказать нам, действителен ли пароль:

Assert.assertEquals(false, validate.isValid());

Moreover, we can learn what errors are returned when the password is invalid. Коды ошибок и описания проверки хранятся вRuleResultDetail:

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"));

Наконец, мы можем изучить метаданные проверки пароля с помощьюRuleResultMetadata:

Integer lengthCount = validate
  .getMetadata()
  .getCounts()
  .get(RuleResultMetadata.CountCategory.Length);
Assert.assertEquals(Integer.valueOf(4), lengthCount);

4. Генерация пароля

Помимо проверки, библиотекаPassay позволяет нам генерировать пароли. We can provide rules which the generator should use.

Чтобы сгенерировать пароль, нам нужен объектPasswordGenerator. Получив его, мы вызываем методgeneratePassword() и передаем списокCharacterRules. Вот пример кода:

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"));

Мы должны знать, что нам нужен объектCharacterData для созданияCharacterRule. Another interesting fact is that the library provides us with EnglishCharacterData. Это перечисление из пяти наборов символов:

  • цифры

  • строчные буквы английского алфавита

  • прописные буквы английского алфавита

  • сочетание строчных и прописных наборов

  • специальные символы

However, nothing can stop us from defining our set of characters. Это так же просто, как реализовать интерфейсCharacterData. Посмотрим, как мы можем это сделать:

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. Правила положительного соответствия

Мы уже узнали, как создавать и проверять пароли. Для этого нам нужно определить набор правил. For that reason, we should know that there are two types of rules available in Passay: positive matching rules and negative matching rules.с

Во-первых, давайте выясним, каковы положительные правила и как мы можем их использовать.

Правила положительного соответствия принимают пароли, которые содержат предоставленные символы, регулярные выражения или вписываются в некоторые ограничения.

Существует шесть правил позитивного соответствия:

  • AllowedCharacterRule - определяет все символы, которые должен включать пароль

  • AllowedRegexRule - определяет регулярное выражение, которому должен соответствовать пароль

  • CharacterRule - определяет набор символов и минимальное количество символов, которые должны быть включены в пароль

  • LengthRule - определяет минимальную длину пароля

  • CharacterCharacteristicsRule - проверяет, соответствует ли парольN заданным правилам.

  • LengthComplexityRule - позволяет нам определять разные правила для разной длины пароля

5.1. Простые правила положительного соответствия

Теперь мы рассмотрим все правила, которые имеют простую конфигурацию. They define a set of legal characters or patterns or an acceptable password’s length.с

Вот краткий пример обсуждаемых правил:

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. Появляются уведомления о том, что пароль слишком короткий и содержит два недопустимых символа. Мы также можем заметить, что пароль не соответствует указанному регулярному выражению.

Более того, нам сообщили, что в нем недостаточно строчных букв.

5.2. CharacterCharacterisitcsRuleс

CharcterCharacterisitcsRule сложнее, чем правила, представленные ранее. To create a CharcterCharacterisitcsRule object, we need to provide a list of CharacterRules. Более того, мы должны указать, скольким из них должен соответствовать пароль. Мы можем сделать это следующим образом:

CharacterCharacteristicsRule characterCharacteristicsRule = new CharacterCharacteristicsRule(
  3,
  new CharacterRule(EnglishCharacterData.LowerCase, 5),
  new CharacterRule(EnglishCharacterData.UpperCase, 5),
  new CharacterRule(EnglishCharacterData.Digit),
  new CharacterRule(EnglishCharacterData.Special)
);

ПредставленныйCharacterCharacteristicsRule требует, чтобы пароль содержал три из четырех предоставленных правил.

5.3. LengthComplexityRuleс

С другой стороны, библиотекаPassay предоставляет намLengthComplexityRule. It allows us to define which rules should be applied to the password of which length. В отличие отCharacterCharacteristicsRule, они позволяют нам использовать все виды правил, а не толькоCharacterRule.

Разберем пример:

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

Как мы видим, для пароля, содержащего от одного до пяти символов, мы применяемCharacterRule. Но для пароля, содержащего от шести до десяти символов, мы хотим, чтобы пароль совпадал сAllowedCharacterRule.

6. Отрицательные правила соответствия

В отличие от правил положительного сопоставления, правила отрицательного сопоставления отклоняют пароли, содержащие указанные символы, регулярные выражения, записи и т. Д.

Давайте выясним, каковы правила отрицательного соответствия:

  • IllegalCharacterRule - определяет все символы, которые пароль не должен содержать

  • IllegalRegexRule - определяет регулярное выражение, которое не должно совпадать

  • IllegalSequenceRule - проверяет, содержит ли пароль недопустимую последовательность символов

  • NumberRangeRule - определяет диапазон чисел, который не должен содержать пароль

  • WhitespaceRule - проверяет, содержит ли пароль пробелы

  • DictionaryRule - проверяет, равен ли пароль какой-либо записи словаря

  • DictionarySubstringRule - проверяет, есть ли в пароле какие-либо словарные записи

  • HistoryRule - проверяет, содержит ли пароль какую-либо историческую ссылку на пароль

  • DigestHistoryRule - проверяет, содержит ли пароль какую-либо переваренную историческую ссылку на пароль

  • SourceRule - проверяет, содержит ли пароль ссылку на исходный пароль

  • DigestSourceRule - проверяет, содержит ли пароль какую-либо ссылку на исходный пароль дайджеста

  • UsernameRule - проверяет, содержит ли пароль имя пользователя

  • RepeatCharacterRegexRule - проверяет, содержит ли пароль повторяющиеся символыASCII

6.1. Простые отрицательные правила соответствия

Во-первых, мы увидим, как можно использовать простые правила, такие какIllegalCharacterRule,IllegalRegexRule и т. Д. Вот короткий пример:

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

Пример показывает нам, как работают описанные правила. Подобно правилам положительного соответствия, они дают нам полный отзыв о проверке.

6.2. Правила словаря

Что делать, если мы хотим проверить, не совпадает ли пароль с предоставленными словами.

По этой причине библиотекаPassay дает нам отличные инструменты для этого. Давайте обнаружимDictionaryRule иDictionarySubstringRule:

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. Полезно, когда у нас есть список самых распространенных или самых простых для взлома паролей. Поэтому разумно запретить пользователям их использовать.

В реальной жизни мы бы наверняка загрузили список слов из текстового файла или базы данных. В этом случае мы можем использоватьWordLists. У него есть три перегруженных метода, которые берут массивReaders и создаютArrayWordList.

6.3. HistoryRule иSourceRule

Кроме того, библиотекаPassay дает намHistoryRule иSourceRule. Они могут проверять пароли по историческим паролям или текстовому контенту из различных источников.

Давайте посмотрим на пример:

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 помогает нам проверить, использовался ли ранее пароль. Поскольку такие методы небезопасны, мы не хотим, чтобы пользователи использовали старые пароли.

С другой стороны,SourceRule позволяет нам проверить, отличается ли пароль от пароля, указанного вSourceReferences. Мы можем избежать риска иметь одинаковые пароли в разных системах или приложениях.

Стоит отметить, что существуют такие правила, какDigestSourceRule иDigestHistoryRule.. Мы рассмотрим их в следующем абзаце.

6.4. Правила дайджеста

В библиотекеPassay есть два правила дайджеста:DigestHistoryRule иDigestSourceRule. Digest rules are intended to work with passwords stored as digest or hash. Следовательно, чтобы определить их, нам нужно предоставить объектEncodingHashBean.

Посмотрим, как это делается:

List historicalReferences = Arrays.asList(
  new PasswordData.HistoricalReference(
    "SHA256",
    "2e4551de804e27aacf20f9df5be3e8cd384ed64488b21ab079fb58e8c90068ab"
));

EncodingHashBean encodingHashBean = new EncodingHashBean(
  new CodecSpec("Base64"),
  new DigestSpec("SHA256"),
  1,
  false
);

На этот раз мы создаемHistoricalReference с помощью метки и закодированного пароля для конструктора. После этого мы создалиEncodingHashBean с правильным кодеком и алгоритмом дайджеста.

Кроме того, мы можем указать количество итераций и то, является ли алгоритм соленым.

После того, как у нас есть bean-компонент кодирования, мы можем проверить наш дайджест-пароль:

PasswordData passwordData = new PasswordData("example!");
passwordData.setPasswordReferences(historicalReferences);

PasswordValidator passwordValidator = new PasswordValidator(new DigestHistoryRule(encodingHashBean));

RuleResult validate = passwordValidator.validate(passwordData);

Assert.assertTrue(validate.isValid());

Мы можем узнать больше оEncodingHashinBean вCryptacular library webpage.

6.5. RepeatCharacterRegexRuleс

Еще одно интересное правило проверки -RepeatCharacterRegexRule. We can use it to check whether password contains repeating ASCII characters.

Вот пример кода:

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с

Последнее правило, которое мы собираемся обсудить в этой главе, -UsernameRule. It enables us to prohibit using the user’s name in the password. 

Как мы узнали ранее, мы должны хранить имя пользователя вPasswordData:

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. Индивидуальные сообщения

БиблиотекаPassay позволяет нам настраивать сообщения, возвращаемые правилами проверки. Firstly, we should define the messages and assign them to error codes.

Мы можем поместить их в простой файл. Посмотрим, насколько это просто:

TOO_LONG=Password must not have more characters than %2$s.
TOO_SHORT=Password must not contain less characters than %2$s.

Как только у нас появятся сообщения, мы должны загрузить этот файл. Наконец, мы можем передать его в объектPasswordValidator.

Вот пример кода:

URL resource = this.getClass().getClassLoader().getResource("messages.properties");
Properties props = new Properties();
props.load(new FileInputStream(resource.getPath()));

MessageResolver resolver = new PropertiesMessageResolver(props);

Как мы видим, мы загрузили файлmessage.properties и передали его в объектProperties. Затем мы можем использовать объектProperties для созданияPropertiesMessageResolver.

Давайте посмотрим на пример использования преобразователя сообщений:

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

Пример ясно показывает, что мы можем перевести все коды ошибок с помощью валидатора, снабженного распознавателем сообщений.

8. Заключение

В этом руководстве мы узнали, как использовать библиотекуPassay. Мы проанализировали несколько примеров того, как библиотека может быть легко использована для проверки пароля. Приведенные правила охватывают большинство распространенных способов обеспечения безопасности пароля.

Но мы должны помнить, что сама библиотека Passay не защищает наш пароль. Во-первых, мы должны изучить общие правила, а затем использовать библиотеку для их реализации.

Все примеры, как всегда, можно найтиover on GitHub.