Advertisement
  1. Code
  2. Web Development

Создайте простой инструмент проверки надежности пароля

Scroll to top
Read Time: 13 min

() translation by (you can also view the original English article)

Обеспечение мгновенной обратной связи является неотъемлемой частью прямо сейчас. Зачем ограничиваться проверкой имен пользователей и адресов электронной почты? Почему бы не расширить это, чтобы обеспечить быструю визуальную обратную связь о надежности пароля, введенного пользователем? Сегодня мы рассмотрим, как создать простую проверку надежности пароля с использованием библиотеки jQuery, регулярных выражений и простого алгоритма.


Слово от автора

Большинство экспертов по безопасности скажут вам, что пользователь всегда является самым слабым звеном. Наиболее безопасные системы уязвимы, когда пользователь выбирает крайне опрометчивый пароль. Имея это в виду, недавняя тенденция, кажется, обеспечивает быструю обратную связь с пользователем относительно надежности пароля, так что пользователь может расширить или изменить пароль, чтобы сделать его более безопасным.

HoversHoversHovers

Сегодня мы собираемся использовать библиотеку jQuery, набор регулярных выражений и очень простой алгоритм для создания базовой проверки надежности пароля. Заинтересовались? Давайте начнем прямо сейчас! Вот демонстрация того, что мы пытаемся построить сегодня:

Demo image

Цели разработки

Наши цели дизайна для этой специфической функциональности относительно невелики.

  • Обеспечить визуальную обратную связь с пользователем относительно надежности его пароля.
  • Обратная связь должна быть мгновенной. Это означает, что не нужно нажимать на кнопку, чтобы проверить прочность.
  • Событие триггера может быть любым из событий клавиатуры. Я выбрал keyup, так как он наиболее подходит для наших конкретных потребностей.
  • Для визуальной обратной связи, изменяя текст только, пока полезно, серьезно недостает. Я захотел изменить цвета фона также, чтобы привлечь внимание пользователя этому.
  • Обеспечьте дополнительную измеримую обратную связь, так что пользователь знает, в каких отделах пароль ощущает недостаток силы и какое это может быть усовершенствовано.

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

План действий

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

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

Алгоритм

The AlgorithmThe AlgorithmThe Algorithm

В целях сохранения краткости и доступности этой статьи я решил использовать очень простой алгоритм. Алгоритм анализирует строку, дает бонусы за дополнительную длину, наличие чисел, символов и букв верхнего регистра и штрафы за ввод только букв или цифр. Мы не будем рассматривать сопоставление общих шаблонов или проверку ввода по словарю, поскольку это выходит за рамки статьи. Если интерес пика, я могу сделать статью об этом в будущем.

Сначала мы проверяем длину входной строки. Если он больше минимальной длины, дайте ему базовую оценку 50. В противном случае установите его равным 0. Затем выполните итерацию по каждому символу строки и проверьте, является ли он символом, цифрой или заглавной буквой. Если это так, запишите это.

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

Проверьте, содержит ли строка только строчные буквы или цифры, и если да, оштрафуйте.

Сложите все числа и определите надежность пароля соответственно.

Это длинный и короткий алгоритм. Это не очень учтивый, но он ловит много плохих паролей. Вы поймете это лучше, как только мы увидим это в коде.

Ядро разметки

HTML-разметка демонстрационной страницы выглядит так:

1
2
<!DOCTYPE html>
3
<html lang="en-GB">
4
<head>
5
<title>Simple Password Strength Checker - by Siddharth for NetTuts</title>
6
<link type="text/css" href="css/style.css" rel="stylesheet" />
7
<script type="text/javascript" src="js/jquery.js"></script>
8
<script type="text/javascript" src="js/mocha.js"></script>
9
</head>
10
<body>
11
12
<div id="container">
13
14
<h1>Create a simple password strength checker</h1>
15
16
<h2 class="bolded">by Siddharth for the lovely folks at Net Tuts</h2>
17
18
<p>Type in your password to get visual feedback regarding the strength of your password.</p>
19
<p>I assure you, I am not stealing your passwords. The form doesn't not submit. You can look through the source if you are suspicious. :)</p> 
20
21
<div class="block">
22
<input id="inputPassword"/>
23
<div id="complexity" class="default">Enter a random value</div>
24
</div>
25
26
<div class="block">
27
<div id="results" class="default">Breakdown of points</div>
28
<div id="details"></div>
29
</div>
30
31
</div>
32
</body>
33
</html>

Не обращайте внимания на все обычные разметки. Обратите внимание на элемент input с идентификатором inputPassword, элементом div с идентификатором сложности, который показывает сложность пароля, и элементом div с идентификатором деталей, который показывает разбивку точек.

Мы также включили библиотеку jQuery и наш собственный файл скрипта. Дополнительные баллы, если вы цените имя нашего файла скрипта.

CSS укладка

1
2
body{
3
  font-family: "Lucida Grande", "Verdana", sans-serif;
4
}
5
6
h1{
7
	font-size: 30px;
8
	padding: 0;
9
	margin: 0;
10
}
11
12
h2{
13
	font-size: 18px;
14
	padding: 0;
15
	margin: 0 5px 30px 0;
16
}
17
18
input{
19
	width: 288px;
20
	height: 30px;
21
	margin: 50px 0 0 0;
22
	padding: 3px 5px;
23
	font-size: 22px;
24
	font-family: "Lucida Grande", "Verdana", sans-serif;
25
}
26
27
#container{
28
	width: 820px;
29
	margin-left: auto;
30
	margin-right: auto;
31
	padding: 50px 0 0 0;
32
}
33
34
.block{
35
	width: 300px;
36
	margin: 0 auto 0 auto;
37
}
38
39
#complexity, #results{
40
	width: 300px;
41
	padding: 3px 0;
42
	height: 20px;
43
	color: #000;
44
	font-size: 14px;
45
	text-align: center;
46
}
47
48
#results{
49
	margin: 30px 0 20px 0;
50
}
51
52
.default{background-color: #CCC;}
53
.weak{background-color: #FF5353;}
54
.strong{background-color: #FAD054;}
55
.stronger{background-color: #93C9F4; }
56
.strongest{background-color: #B6FF6C;}
57
58
span.value{
59
	font-weight:bold;
60
	float: right;
61
}

Просто котельная плита CSS для макетов и типографики. У нас есть куча классов внизу для каждого индивидуального рейтинга силы. Мы добавим их к элементам при необходимости.

Реализация JavaScript

Теперь, когда у нас есть надежная структура и некоторые базовые стили, мы можем приступить к написанию необходимой функциональности. Обратите внимание, что мы широко используем jQuery. При необходимости сделайте ссылку на CDN Google.

Переменные и обработка событий

Так как будет продолжаться большое количество жонглирования числами, нам понадобится множество переменных для хранения значений. Поскольку это демонстрационный, а не производственный код, я решил объявить переменные глобальными и обращаться к ним через вспомогательные методы, а не объявлять их внутренне, а затем передавать их функциям.

1
2
	var strPassword;
3
	var charPassword;
4
	var complexity = $("#complexity");
5
	var minPasswordLength = 8;
6
	var baseScore = 0, score = 0;
7
	
8
	var num = {};
9
	num.Excess = 0;
10
	num.Upper = 0;
11
	num.Numbers = 0;
12
	num.Symbols = 0;
13
14
	var bonus = {};
15
	bonus.Excess = 3;
16
	bonus.Upper = 4;
17
	bonus.Numbers = 5;
18
	bonus.Symbols = 5;
19
	bonus.Combo = 0; 
20
	bonus.FlatLower = 0;
21
	bonus.FlatNumber = 0;

Названия переменных довольно стандартные, но я бы все равно дал краткое изложение. strPassword содержит значение поля ввода, charPassword - это массив, содержащий каждый символ строки, сложность содержит ссылку на элемент div. Мы также определяем минимальную длину пароля, оценку и базовую оценку.

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

Не забывайте соединять обработчик событий к событию.

1
2
	$("#inputPassword").bind("keyup", checkVal);

checkVal - обработчик событий, который мы создадим в просто крошечном бите.

Обработчик событий

1
2
function checkVal()
3
{
4
	if (charPassword.length >= minPasswordLength)
5
	{
6
		baseScore = 50;	
7
		analyzeString();	
8
		calcComplexity();		
9
	}
10
	else
11
	{
12
		baseScore = 0;
13
	}
14
	
15
	outputResult();
16
}

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

Если это меньше, чем ожидаемая длина, мы просто устанавливаем базовый счет на 0.

Затем мы вызываем функцию outputResult, которая заботится о смысле вычисляемых вычислений. Ниже мы увидим, как это работает.

Анализ входных данных

1
2
function analyzeString ()
3
{	
4
	for (i=0; i<charPassword.length;i++)
5
	{
6
		if (charPassword[i].match(/[A-Z]/g)) {num.Upper++;}
7
		if (charPassword[i].match(/[0-9]/g)) {num.Numbers++;}
8
		if (charPassword[i].match(/(.*[!,@,#,$,%,^,&,*,?,_,~])/)) {num.Symbols++;} 
9
	}
10
	
11
	num.Excess = charPassword.length - minPasswordLength;
12
	
13
	if (num.Upper && num.Numbers && num.Symbols)
14
	{
15
		bonus.Combo = 25; 
16
	}
17
18
	else if ((num.Upper && num.Numbers) || (num.Upper && num.Symbols) || (num.Numbers && num.Symbols))
19
	{
20
		bonus.Combo = 15; 
21
	}
22
	
23
	if (strPassword.match(/^[\sa-z]+$/))
24
	{ 
25
		bonus.FlatLower = -15;
26
	}
27
	
28
	if (strPassword.match(/^[\s0-9]+$/))
29
	{ 
30
		bonus.FlatNumber = -35;
31
	}
32
}

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

Во-первых, нам нужно выяснить состав рассматриваемой строки. Например, нам нужно выяснить, содержит ли строка буквы в верхнем регистре, количество символов и, если да, то сколько их присутствует. Имея это в виду, мы перебираем массив символов и проверяем каждый символ, чтобы увидеть его тип. Метод match позволяет сопоставить строку с регулярным выражением. Если вы новичок в регулярных выражениях, я предлагаю вам прочитать замечательную статью Василия здесь.

Далее мы должны определить разницу между длиной входной строки и указанной минимальной длиной пароля. Это дает нам избыточное количество персонажей для игры.

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

Наконец, мы проверяем, является ли строка плоской: содержит ли она только строчные буквы или только цифры. Мы проверяем это с помощью регулярного выражения и, если это так, оштрафуем пароль для этой практики.

Вычислить сложности

1
2
function calcComplexity()
3
{
4
	score = baseScore + (num.Excess*bonus.Excess) + (num.Upper*bonus.Upper) + (num.Numbers*bonus.Numbers) + 
5
(num.Symbols*bonus.Symbols) + bonus.Combo + bonus.FlatLower + bonus.FlatNumber;	
6
}

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

Обновление пользовательского интерфейса

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

Points
Points
Points
Points
1
2
function outputResult()
3
{
4
	if ($("#inputPassword").val()== "")
5
	{ 
6
		complexity.html("Enter a random value").addClass("default");
7
	}
8
	else if (charPassword.length < minPasswordLength)
9
	{
10
		complexity.html("At least " + minPasswordLength+ " characters please!").addClass("weak");
11
	}
12
	else if (score<50)
13
	{
14
		complexity.html("Weak!").addClass("weak");
15
	}
16
	else if (score>=50 && score<75)
17
	{
18
		complexity.html("Average!").addClass("strong");
19
	}
20
	else if (score>=75 && score<100)
21
	{
22
		complexity.html("Strong!").addClass("stronger");
23
	}
24
	else if (score>=100)
25
	{
26
		complexity.html("Secure!").addClass("strongest");
27
	}
28
}

Ничего необычного здесь, но мы будем проходить это построчно.

Сначала мы проверим, является ли ввод пустым. Если это так, измените текст результата и добавьте класс по умолчанию, чтобы изменить его цвет фона на его первоначальный серый.

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

По мере увеличения оценки мы соответственно меняем текст и добавляем необходимые классы. Не стесняйтесь изменять базовые оценки для каждого рейтинга. Я просто ввел ненаучные ценности, чтобы запустить демо.

Обновление подробная разбивка

Points

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

1
2
function outputResult()
3
{
4
	// Previous Code

5
    
6
    $("#details").html("Base Score :<span class=\"value\">" + baseScore  + "</span>"
7
				  + "<br />Length Bonus :<span class=\"value\">" + (num.Excess*bonus.Excess) + " ["+num.Excess+"x"+bonus.Excess+"]</span> " 
8
				  + "<br />Upper case bonus :<span class=\"value\">" + (num.Upper*bonus.Upper) + " ["+num.Upper+"x"+bonus.Upper+"]</span> "
9
				  + "<br />Number Bonus :<span class=\"value\"> " + (num.Numbers*bonus.Numbers) + " ["+num.Numbers+"x"+bonus.Numbers+"]</span>"
10
				  + "<br />Symbol Bonus :<span class=\"value\"> " + (num.Symbols*bonus.Symbols) + " ["+num.Symbols+"x"+bonus.Symbols+"]</span>"
11
				  + "<br />Combination Bonus :<span class=\"value\"> " + bonus.Combo + "</span>"
12
				  + "<br />Lower case only penalty :<span class=\"value\"> " + bonus.FlatLower + "</span>"
13
				  + "<br />Numbers only penalty :<span class=\"value\"> " + bonus.FlatNumber + "</span>"
14
				  + "<br />Total Score:<span class=\"value\"> " + score  + "</span>" 
15
}

Эта часть не так запутана, как кажется. Позволь мне объяснить.

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

Это похоже на внедрение обычного HTML в элемент, за исключением того, что мы поместили пару переменных внутрь, чтобы детали могли быть обновлены мгновенно. Каждое значение получает класс значения, чтобы сделать его жирным. Мы также отображаем количество специальных символов и их множитель, чтобы пользователь мог определить, какие элементы получают больший вес.

Несколько настроек

На данный момент, есть 2 ошибки, которые появляются.

  • Если вы введете длинный пароль, а затем удалите текстовое поле, цвета фона не изменятся.
  • В этом же сценарии детали точек не обновляются должным образом.

Мы будем решать их по одному.

Для первой ошибки основной причиной является тот факт, что мы не удаляем все остальные классы. Это не будет проблемой, если последние добавленные классы будут иметь приоритет над другими. К сожалению, это не так. Вот быстрое решение.

1
2
function outputResult()
3
{
4
	if ($("#inputPassword").val()== "")
5
	{ complexity.html("Enter a random value").removeClass("weak strong stronger strongest").addClass("default");}
6
	else if (charPassword.length < minPasswordLength)
7
	{complexity.html("At least " + minPasswordLength+ " characters please!").removeClass("strong stronger strongest").addClass("weak");}
8
	else if (score<50)
9
	{complexity.html("Weak!").removeClass("strong stronger strongest").addClass("weak");}
10
	else if (score>=50 && score<75)
11
	{complexity.html("Average!").removeClass("stronger strongest").addClass("strong");}
12
	else if (score>=75 && score<100)
13
	{complexity.html("Strong!").removeClass("strongest").addClass("stronger");}
14
	else if (score>=100)
15
	{complexity.html("Secure!").addClass("strongest");}
16
17
	// Details updating code

18
}

Вы, вероятно, спрашиваете, почему мы не удаляем каждый класс здесь. Ответ прост: мы используем один из основных атрибутов CSS: каскадирование. Если вы заметите порядок объявления каждого класса в CSS-файле, вы заметите, что default происходит первым, а самый сильный - последним, что означает, что если элемент имеет самый сильный класс, он будет переопределять любые изменения, сделанные любым классом над ним. Таким образом, мы должны удалить только те классы, которые находятся ниже соответствующего класса. Например, чтобы элемент имел сильный, нам нужно удалить более сильные и самые сильные классы.

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

1
2
function init()
3
{
4
	strPassword= $("#inputPassword").val();
5
	charPassword = strPassword.split("");
6
		
7
	num.Excess = 0;
8
	num.Upper = 0;
9
	num.Numbers = 0;
10
	num.Symbols = 0;
11
	bonus.Combo = 0; 
12
	bonus.FlatLower = 0;
13
	bonus.FlatNumber = 0;
14
	baseScore = 0;
15
	score =0;
16
}
1
2
function checkVal()
3
{
4
	init();
5
    
6
	// Other code

7
}

Ограничения

Limitation with the current implementation

Если вы немного поигрались с демо, вы заметите, что Pa $$ W0rd $ становится безопасным паролем, хотя на самом деле он скоро будет взломан. Это связано с простотой нашего алгоритма здесь. Мы не проверяем замены персонажей. Или общие пароли или шаблоны в этом отношении. Выполнение таких вещей увеличило бы сложность этого урока, уменьшив его доступность, и то, и другое я не хотел для этой конкретной статьи.

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

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

Заключение 

И вот что у вас есть: как добавить удобную для пользователя функциональность, возможность сообщить пользователю силу пароля, который он только что ввел, в ваши проекты. Надеюсь, вы нашли этот урок интересным, и он был вам полезен. Не стесняйтесь многократно использовать этот код в других местах своих проектов и звоните сюда, если у вас возникнут трудности.

Вопросы? Хорошие вещи, чтобы сказать? Критицизмы? Нажмите на раздел комментариев и оставьте мне комментарий. Удачного кодирования!

  • Подпишитесь на нас в Twitter или подпишитесь на ленту Nettuts + RSS для получения лучших учебных материалов по веб-разработке.


Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.