Как я могу безопасно хранить пароли моих пользователей?

Насколько это безопаснее, чем обычный MD5? Я только начал изучать безопасность пароля. Я довольно новичок в PHP.

$salt = 'csdnfgksdgojnmfnb';

$password = md5($salt.$_POST['password']);
$result = mysql_query("SELECT id FROM users
                       WHERE username = '".mysql_real_escape_string($_POST['username'])."'
                       AND password = '$password'");

if (mysql_num_rows($result) < 1) {
    /* Access denied */
    echo "The username or password you entered is incorrect.";
} 
else {
    $_SESSION['id'] = mysql_result($result, 0, 'id');
    #header("Location: ./");
    echo "Hello $_SESSION[id]!";
}

7 ответов

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

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


Новый API паролей PHP (5.5.0+)

Если вы используете PHP версии 5.5.0 или новее, вы можете использовать новый API упрощенного хеширования паролей

Пример кода с использованием API паролей PHP:

<?php
// $hash is what you would store in your database
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT, ['cost' => 12]);

// $hash would be the $hash (above) stored in your database for this user
$checked = password_verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}

(Если вы все еще используете устаревшую версию 5.3.7 или новее, вы можете установить https://github.com/ircmaxell/password_compat, чтобы иметь доступ к встроенным функциям)


Улучшение соленых хэшей: добавить перец

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

Существует простой класс, который безопасно реализует этот шаблон, я рекомендую: Netsilik / PepperedPasswords ( github).
Он поставляется с лицензией MIT, поэтому вы можете использовать его по своему усмотрению, даже в проприетарных проектах.

Пример использования кода Netsilik/PepperedPasswords:

<?php
use Netsilik/Lib/PepperedPasswords;

// Some long, random, binary string, encoded as hexadecimal; stored in your configuration (NOT in your Database, as that would defeat the entire purpose of the pepper).
$config['pepper'] = hex2bin('012345679ABCDEF012345679ABCDEF012345679ABCDEF012345679ABCDEF');

$hasher = new PepperedPasswords($config['pepper']);

// $hash is what you would store in your database
$hash = $hasher->hash($_POST['password']);

// $hash would be the $hash (above) stored in your database for this user
$checked = $hasher->verify($_POST['password'], $hash);
if ($checked) {
    echo 'password correct';
} else {
    echo 'wrong credentials';
}


Старая стандартная библиотека

Обратите внимание: вам это больше не нужно! Это только для исторических целей.

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

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

<?php
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 $hash (above) 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)
  • другие

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

Подробнее о схемах хранения паролей читайте в блоге Jeff Atwood: " Возможно, вы неправильно храните пароли"

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

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

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

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

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

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

С PHP 5.5 (то, что я описываю, доступно даже для более ранних версий, см. Ниже), я хотел бы предложить использовать его новое встроенное решение: password_hash() а также password_verify(), Он предоставляет несколько опций для достижения необходимого уровня защиты паролем (например, путем указания параметра "стоимость" через $options массив)

<?php
var_dump(password_hash("my-secret-password", PASSWORD_DEFAULT));

$options = array(
    'cost' => 7, // this is the number of rounds for bcrypt
    // 'salt' => 'TphfsM82o1uEKlfP9vf1f', // you could specify a salt but it is not recommended
);
var_dump(password_hash("my-secret-password", PASSWORD_BCRYPT, $options));
?>

вернусь

string(60) "$2y$10$w2LxXdIcqJpD6idFTNn.eeZbKesdu5y41ksL22iI8C4/6EweI7OK."
string(60) "$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d."

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

Поэтому при проверке пароля (например, когда пользователь входит в систему), при использовании бесплатного password_verify() Функция извлекает необходимые параметры шифрования из самого хэша пароля.

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

Проверка работает следующим образом:

var_dump(password_verify("my-secret-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));
var_dump(password_verify("wrong-password", '$2y$10$BjHJbMCNWIJq7xiAeyFaHOGaO0jjNoE11e0YAer6Zu01OZHN/gk6K'));

var_dump(password_verify("my-secret-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));
var_dump(password_verify("wrong-password", '$2y$07$TphfsM82o1uEKlfP9vf1fOKohBqGVXOJEmnUtQu7Y1UMft1R4D3d.'));

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

Есть небольшая библиотека (один файл PHP), которая даст вам PHP 5.5 password_hash в PHP 5.3.7+: https://github.com/ircmaxell/password_compat

Я хочу добавить:

  • Не ограничивайте пароли пользователей длиной

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

  • Не отправляйте пароли пользователей по электронной почте

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

  • Обновите хеши паролей пользователей

Хеш пароля может быть устаревшим (параметры алгоритма могут быть обновлены). Используя функцию password_needs_rehash() Вы можете проверить это.

Я не против. Мистер Этвуд писал о силе MD5 по сравнению с радужными столами, и, в основном, с такой длинной солью, как ты сидишь довольно (хотя некоторые случайные знаки препинания / числа могут улучшить ее).

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

Вот система входа PHP + CouchDB.apache.org, которая не хранит пароли в виде открытого текста.

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

Код для входа в CMS: https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/boot.php#L56 звонки https://github.com/nicerapp/niceraeepp/blob/24ffrapps/nicerapp/blob/24ffrapps/blob/24ff9d03d04d06d06d06d05 L171

бизнес-код для конкретного приложения (-ов):https://github.com/nicerapp/nicerapp/blob/24ff0ca317b28c1d91aee66041320976a6d76da7/nicerapp/ajax_login.php#L87 звонки https://github.com/nicerapp/nicerapp13/nicerapp13/blogger/b04e6e6d06d06d6d06d6d6d6d06a08a8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa functions.php # L230, который, в свою очередь, вызывает: https://github.com/nicerapp/nicerapp/blob/2d479b3e22dce9e7073525481b775f1bf7389634/nicerapp/apps/nicer.app/webmail/recrypt.php#L2

и отредактировать данные конфигурации приложения веб-почты в базе данных:https://github.com/nicerapp/nicerapp/blob/main/nicerapp/apps/nicer.app/webmail/ajax_editConfig.php

Другие вопросы по тегам