Как измерить надежность пароля? - PullRequest
8 голосов
/ 23 октября 2009

Я искал эффективный алгоритм, который мог бы дать мне точное представление о том, насколько надежен пароль.

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

Ответы [ 6 ]

19 голосов
/ 23 октября 2009

Это выросло до моего общего умственного опыта по работе с паролями в PHP / MySQL. Представленные здесь идеи, как правило, не мои, но лучшие из того, что я нашел на сегодняшний день.


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

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

Разрешить относительно слабые пароли, но хранить количество неудачных входов в систему на пользователя и требовать проверки или проверки пароля по электронной почте, если вы превысите его. Я установил максимальные ошибки на 5.

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

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

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


Я обнаружил, что проверка словарных слов перед отправкой неэффективна, так как нужно либо отправить клиенту словарь в javascript, либо отправить ajax-запрос на изменение поля. Я делал это некоторое время, и это работало нормально, но мне не нравился трафик, который он генерировал.

Проверка на наличие слабых по своей сути паролей минус слова из словаря - это практическая клиентская сторона с некоторым простым javascript.

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

Как только вы довольны паролем, они выбрали сначала зашифровать его с помощью PHP, а затем сохранить. Следующая функция шифрования паролей тоже не моя идея, но решает ряд проблем. Шифрование в PHP не позволяет людям на общем сервере перехватывать ваши незашифрованные пароли. Добавление чего-либо для пользователя, которое не изменится (я использую электронную почту, так как это имя пользователя для моих сайтов) и добавление хэша (SALT - это короткая постоянная строка, которую я изменяю для каждого сайта) повышает устойчивость к атакам. Поскольку ОСВ находится внутри пароля, и пароль может быть любой длины, становится почти невозможно атаковать это с помощью радужной таблицы. С другой стороны, это также означает, что люди не могут изменить свою электронную почту, и вы не можете изменить ОСВ, не аннулировав пароль каждого.

РЕДАКТИРОВАТЬ: я бы сейчас рекомендовал использовать PhPass вместо моей собственной функции здесь или просто полностью забыть логины пользователей и использовать OpenID вместо.

function password_crypt($email,$toHash) {
  $password = str_split($toHash,(strlen($toHash)/2)+1);
  return hash('sha256', $email.$password[0].SALT.$password[1]); 
}

Мой Jqueryish измеритель пароля на стороне клиента. Цель должна быть div. Его ширина будет меняться от 0 до 100, а цвет фона будет меняться в зависимости от классов, обозначенных в скрипте. Опять в основном украденные из других вещей, которые я нашел:

$.updatePasswordMeter = function(password,username,target) {
$.updatePasswordMeter._checkRepetition = function(pLen,str) {
res = ""
for ( i=0; i<str.length ; i++ ) {
    repeated=true;
    for (j=0;j < pLen && (j+i+pLen) < str.length;j++)
        repeated=repeated && (str.charAt(j+i)==str.charAt(j+i+pLen));
    if (j<pLen) repeated=false;
    if (repeated) {
        i+=pLen-1;
        repeated=false;
    }
    else {
        res+=str.charAt(i);
    };
};
return res;
};
var score = 0;
var r_class = 'weak-password';
//password < 4
if (password.length < 4 || password.toLowerCase()==username.toLowerCase()) { 
target.width(score + '%').removeClass("weak-password okay-password good-password strong-password"
).addClass(r_class);
  return true;
} 
//password length
score += password.length * 4;
score += ( $.updatePasswordMeter._checkRepetition(1,password).length - password.length ) * 1;
score += ( $.updatePasswordMeter._checkRepetition(2,password).length - password.length ) * 1;
score += ( $.updatePasswordMeter._checkRepetition(3,password).length - password.length ) * 1;
score += ( $.updatePasswordMeter._checkRepetition(4,password).length - password.length ) * 1;
//password has 3 numbers
if (password.match(/(.*[0-9].*[0-9].*[0-9])/))  score += 5; 

//password has 2 symbols
if (password.match(/(.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~])/)) score += 5; 

//password has Upper and Lower chars
if (password.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/))  score += 10; 

//password has number and chars
if (password.match(/([a-zA-Z])/) && password.match(/([0-9])/))  score += 15; 
//
//password has number and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([0-9])/))  score += 15; 

//password has char and symbol
if (password.match(/([!,@,#,$,%,^,&,*,?,_,~])/) && password.match(/([a-zA-Z])/))  score += 15; 

//password is just a nubers or chars
if (password.match(/^\w+$/) || password.match(/^\d+$/) )  score -= 10; 

//verifing 0 < score < 100
score = score * 2;
if ( score < 0 )  score = 0;
if ( score > 100 )  score = 100;
if (score > 25 ) r_class = 'okay-password';
if (score > 50  ) r_class = 'good-password';
if (score > 75 ) r_class = 'strong-password';
target.width(score + '%').removeClass("weak-password okay-password good-password strong-password"
).addClass(r_class);
return true;
};
7 голосов
/ 23 октября 2009

Принципиально вы хотите предотвратить основные виды атак

  • Словарь атак
  • Атаки грубой силой

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

Быстрый поиск в Google позволил найти решения, которые учитывают атаки методом перебора (сложный пароль), но не атаки по словарю. PHP Password Strength Meter из этот список проверок надежности выполняет проверку на стороне сервера, поэтому его можно расширить для проверки словаря.

EDIT:

Кстати ... вам также следует ограничить количество попыток входа в систему на пользователя. Это сделает оба типа атак менее вероятными. Эффективным, но не удобным для пользователя является блокирование учетной записи после X неудачных попыток и требует сброса пароля. Более удобный, но больше усилий - сократить время между попытками входа в систему. Вы также можете потребовать CAPTCHA после первых нескольких попыток входа в систему (что требуется при переполнении стека после слишком большого количества изменений или для совсем новых пользователей).

3 голосов
/ 23 октября 2009

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

Хороший пример этого с использованием javascript можно найти здесь:

http://marketingtechblog.com/programming/javascript-password-strength/

2 голосов
/ 24 октября 2009

Как отметил Дарен Швенке, вам лучше работать над безопасностью самостоятельно, а не отдавать это в руки пользователя .

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

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

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

Вы можете очень легко взломать свой собственный алгоритм: просто сделайте 10/10 отметку:

  • 0 - пароль нулевой длины;
  • + 2 на каждые 8 ​​символов в пароле (15 должно быть безопасной длиной);
  • + 1 для использования буквы, +2 для использования 2 букв;
  • + 1 для использования числа, +2 для использования 2 числа;
  • + 1 для использования неалфавитных символов, +2 для 2.

Вам не нужно проверять богоподобные пароли (есть ли заглавные буквы, где расположены специальные символы и т. Д.), Ваши пользователи не работают в индустрии банковских / военных / секретных услуг / ежемесячных фильмов на Python, не так ли?

Вы можете написать это за час без сумасшедших навыков JavaScript.

И в любом случае, подтвердите пароль и переместите весь код безопасности на стороне сервера. Если вы можете делегировать аутентификацию (например, открытый идентификатор), даже лучше.

0 голосов
/ 26 января 2016

Не скатывайся!

Эксперты по криптографии не одобряют криптографию, созданную самим по себе по понятным причинам.

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

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

Это сложная проблема

Существует значительная сложность, связанная с проблемой измерения надежности пароля. Чем больше исследований я выполняю по этому вопросу, тем больше понимаю, что это «однонаправленная» проблема; то есть нельзя измерить «сложность» (вычислительную стоимость) взлома пароля эффективно . Скорее, более эффективно предоставлять требования к сложности и измерять способность пароля соответствовать им.

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

Представьте себе, что Джон Потрошитель (или аналогичный инструмент) сопоставляет данный пароль; Чтобы взломать приличный пароль могут потребоваться дни, месяцы, чтобы взломать хороший пароль, и пока солнце не сгорит, чтобы взломать исключительный пароль. Это непрактичный способ измерения надежности пароля.

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

Жизнеспособное решение

В Openwall доступна отдельная утилита с названием passwdqc (предположительно, обозначающая Проверка качества пароля ). Разработчик Openwall, Solar Designer, действительно является добросовестным экспертом в области криптографии (его работы говорят сами за себя), и поэтому он вполне способен создать такой инструмент.

Для моего конкретного варианта использования это гораздо более привлекательное решение, чем использование непродуманного фрагмента JavaScript, живущего в каком-то темном уголке Интернета.

Определение параметров для ваших конкретных потребностей - самая трудная часть. Реализация является простой частью.

Практический пример

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

В этом примере предполагается, что мы вводим полный список паролей в скрипт PHP. Само собой разумеется, что если вы делаете это с реальными паролями (например, с паролями, сброшенными из диспетчера паролей), следует соблюдать крайнюю осторожность в отношении обработки паролей. Простая запись незашифрованного дампа паролей на диск ставит под угрозу безопасность ваших паролей!

passwords.csv:

"Title","Password"
"My Test Password","password123"
"Your Test Password","123456!!!"
"A strong password","NFYbCoHC5S7dngitqCD53tvQkAu3dais"

password-check.php

<?php

//A few handy examples from other users:
//http://php.net/manual/en/function.str-getcsv.php#117692

$csv = array_map('str_getcsv', file('passwords.csv'), [',']);

array_walk($csv, function(&$a) use ($csv) {
    $a = array_combine($csv[0], $a);
});

//Remove column header.

array_shift($csv);

//Define report column headers.

$results[] = [
    'Title',
    'Result',
    'Exit Code',
];

$i = 1;

foreach ($csv as $p) {
    $row['title'] = $p['Title'];

    //If the value contains a space, it's considered a passphrase.

    $isPassphrase = stristr($p['Password'], ' ') !== false ? true : false;

    $cmd = 'echo ' . escapeshellarg($p['Password']) . ' | pwqcheck -1 min=32,24,22,20,16 max=128';

    if ($isPassphrase) {
        $cmd .= ' passphrase=3';
    }
    else {
        $cmd .= ' passphrase=0';
    }

    $output = null;
    $exitCode = null;

    $stdOut = exec($cmd, $output, $exitCode);

    //Exit code 0 represents an unacceptable password (not an error).
    //Exit code 1 represents an acceptable password (it meets the criteria).

    if ($exitCode === 0 || $exitCode === 1) {
        $row['result'] = trim($stdOut);
        $row['exitCode'] = $exitCode;
    }
    else {
        $row['result'] = 'An error occurred while calling pwqcheck';
        $row['exitCode'] = null;
    }

    $results[$i] = $row;

    $i++;
}

$reportFile = 'report.csv';

$fp = @fopen($reportFile, 'w');

if ($fp !== false) {
    foreach ($results as $p) {
        fputcsv($fp, $p);
    }

    fclose($fp);
}
else {
    die($reportFile . ' could not be opened for writing (destination is not writable or file is in use)');
}

exit;

Результирующий report.csv:

Title,Result,"Exit Code"
"My Test Password","Bad passphrase (too short)",1
"Your Test Password","Bad passphrase (too short)",1
"A strong password",OK,0

Обертывание-Up

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

Очевидно, что этот подход не идеален для определенных случаев использования (например, «измеритель надежности пароля», реализованный «на стороне клиента»). Несмотря на это, было бы тривиально сделать AJAX-вызов к ресурсу на стороне сервера, который возвращает ответ «прошел / не прошел», используя подход, описанный выше, но такой подход должен предполагать возможность злоупотребления (например, атаки DoS) и потребовать безопасная связь между клиентом и сервером, а также принятие рисков, связанных с передачей нехэшированного пароля.

0 голосов
/ 23 октября 2009

Я не могу придумать конкретный алгоритм для проверки надежности пароля. Что мы делаем, мы определяем несколько критериев и, когда пароль соответствует критерию, мы добавляем 1 к его оценке. Когда пароль достигает порогового значения, пароль надежный. В противном случае это слабый.

Вы можете определить много разных уровней прочности, если с разным порогом, или вы можете определить другое значение для определенных критериев. Например, если пароль имеет 5 символов, мы добавляем 1, но если он получил 10, то мы добавляем 2.

вот список критериев для проверки на

Длина (от 8 до 12 в порядке, больше - лучше) Содержит строчную букву Содержит заглавную букву Заглавная буква НЕ первая. Содержит номер Содержит символы последний символ НЕ является символом, похожим на человека (например:. или!) Не похоже на словарное слово. В некоторых хитрых паролях есть библиотека заменителей слов и букв (например, Библиотека -> L1br @ ry)

Надеюсь, что поможет.

...