Каковы недостатки этого метода аутентификации пользователя?

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

Некоторая информация, которая может быть полезна до начала. Я использую mod_rewrite для моего MVC-url. Пароли зашифрованы с солью 24 символов, уникальной для каждого пользователя. mysql_real_escape_string и/или переменная typecasting во всем, что происходит, и htmlspecialchars на все, что выходит.

Пошаговый процесс:

Верх каждой страницы:

session_start();
session_regenerate_id();

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

На каждой странице проверьте наличие файлов cookie. Если файлы cookie установлены, скопируйте их значения в переменные сеанса. Затем сравните $_SESSION ['name'] и $_SESSION ['hash'] с базой данных MySQL. Уничтожьте все файлы cookie и переменные сеанса, если они не совпадают, чтобы они снова вошли в систему.

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

Я попытался протестировать все распространенные атаки, такие как XSS и CSRF, но, возможно, я просто недостаточно хорош для взлома моего собственного сайта! Моя система кажется слишком простой, чтобы она была на самом деле безопасной (код безопасности составляет всего 100 строк). Что мне не хватает?

Изменить: для вызова функций с контроллера все, что использует ничего, кроме запросов SELECT, потребует данных $_POST для подтверждения удаления, например, в дополнение к требованиям к рангу пользователя.

Я также потратил много времени на поиск уязвимостей с помощью строки mysql_real_escape, но я не нашел информации, которая является актуальной (все прошло от нескольких лет назад, по крайней мере, и, по-видимому, было исправлено). Все, что я знаю, это то, что проблема связана с кодировкой. Если эта проблема все еще существует сегодня, как ее избежать?

Функция шифрования, которую я заимствовал где-то и изменил:

public function encrypt($str, $salt = NULL) {
    if ($salt == NULL) $salt = substr(md5(uniqid(rand(), true)), 0, 24);
    else $salt = substr($salt, 0, 24);
    return $salt.sha1($salt.$str);
}

Ответ 1

Сделайте себе одолжение и используйте стандартную библиотеку для хэширования ваших паролей.

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

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

пример кода с использованием phpass (v0.2):

require('PasswordHash.php');

$pwdHasher = new PasswordHash(8, FALSE);

// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );

// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

PHPass реализован в некоторых довольно известных проектах:

  • phpBB3
  • WordPress 2.5+, а также bbPress
  • версия Drupal 7 (модуль доступен для Drupal 5 и 6)
  • другие

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

Что бы вы ни делали, если вы идете на "Я сделаю это сам, спасибо", больше не использовать MD5. Это хороший алгоритм хэширования, но он полностью нарушен для целей безопасности.

В настоящее время, используя crypt, лучше всего использовать CRYPT_BLOWFISH.
CRYPT_BLOWFISH в PHP - это реализация хэша Bcrypt. Bcrypt основан на блочном шифре Blowfish, используя его дорогостоящую настройку ключа, чтобы замедлить алгоритм.

Для получения дополнительной информации о схемах хранения паролей вы также можете прочитать Jeff сообщение в блоге: Вероятно, вы храните пароли неверно

Ответ 2

Я не вижу никакой реальной профилактики для атак CSRF. CSRF (насколько я понимаю) наиболее часто упускает из виду уязвимость на веб-сайтах. Многие из крупных парней были взломаны с помощью уязвимостей CSRF.

В настоящее время лучшим решением этой проблемы является использование токенов синхронизатора.

Вам также лучше было бы быть очень религиозным относительно правильного ввода пользовательского ввода/кодирования. Вещи, которые вставляются в базу данных, должны быть экранированы, и все, что возвращается обратно пользователю, должно быть закодировано на основе их контекста: CSS, HTML, JavaScript и т.д. Все должны быть закодированы по-разному.

Кроме того, вы не должны комбинировать SHA-1 с MD5. Хотя SHA-1 сильнее MD5, вы существенно ослабляете его, комбинируя его с MD5. Кроме того, ни один из этих алгоритмов не рекомендуется использовать в новых приложениях. В настоящее время вы должны использовать SHA-256 (он доступен из коробки в PHP).

Ответ 3

Пытаясь переоценить подход, вы можете подорвать безопасность.

Какой обработчик сеанса вы используете? Вы проверили, что session_regenerate_id() переименовывает существующий сеанс, а не делает его копию? Если последнее, то вы создаете множество файлов сеанса, которые намного проще найти при случайном поиске.

Как вы работаете с сеансами разделения пользователей? Эта строка кода будет прерываться в зависимости от браузера и того, как пользователь разделяет сеанс.

Единственное место, где вы должны использовать session_regenerate_id(), - это когда вы аутентифицируете пользователя и когда пользователь выходит из системы.

mysql_real_escape_string и/или переменная typecasting во всем, что происходит в

НЕТ, нет, нет. Это продолжается здесь.

Вы не меняете представление входящих данных. Обязательно/проверяйте/вводите, и вы всегда должны/дезинфицировать/выводить - вы не выполняете/не дезинфицируете/не вводите.

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

Ничего здесь, что улучшает вашу безопасность

Храните хэш и имя пользователя открытого текста в переменных сеанса и дублируйте файлы cookie, если "Запомнить меня" отмечен

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

На каждой странице проверьте наличие файлов cookie. Если файлы cookie установлены, скопируйте их значения в переменные сеанса.

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

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

С.

Ответ 4

с session_regenerate_id(); вы сделаете кнопку "Назад" в своем браузере непригодной. Но все же в сочетании с функцией "запомнить меня" она становится бесполезной.
Я не вижу защиты CSRF в вашем описании
Нет никакой проблемы с строкой mysql_real_escape

Ответ 5

Возможно, вы захотите проверить user.rank на белый список, чтобы убедиться, что это значение существует в таблице поиска и является действительным (активным, а не удаленным и т.д.), а также для принудительного ввода типов и диапазона.

Что касается токенов, вам нужно будет создать новый токен для каждой страницы, которая рассчитывает получить данные GET/POST из формы. Если сеанс взломан, то токен для сеанса может быть недостаточным. Установка более короткого таймаута для сеанса может уменьшиться.

Не доверяйте чему-либо из файла cookie сразу, рассмотрите возможность использования http://php.net/manual/en/book.filter.php перед тем, как приступить к сеансу.

Если вы планируете иметь административную панель для системы, она идеально подходит для обеспечения безопасности паролей, выбор имени входа в административный администратор вручную (вместо входа в учетную запись администратора/пароля при настройке).

В черный список входят обычные имена пользователей, такие как "a", "DROP DATABASE..." и "Administrator", вы знаете упражнение.

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

Ответ 6

"Пароли шифруются sha1 и md5"

Зачем нужно использовать две хэш-функции? Думаю, вы это делаете из-за отсутствия понимания (без обид!). Вы должны прочитать эту статью о схемах защищенных паролей (подсказка: используйте bcrypt).