Безопасность PHP: Функция makePasswordKey — как правильно генерировать хэш-ключ пароля с использованием соли (salt) для хранения в БД?

Безопасное хранение паролей — одна из ключевых задач при разработке веб-приложений на PHP. Использование простого MD5 или SHA1 без соли давно считается небезопасным. Рассмотрим, как правильно реализовать функцию makePasswordKey с применением соли.

## Что такое соль (salt)?

Соль — это случайная строка, которая добавляется к паролю перед хэшированием. Это защищает от атак по радужным таблицам (rainbow tables) и делает одинаковые пароли разных пользователей непохожими в хранилище.

## Современный подход: password_hash()

Начиная с PHP 5.5, рекомендуется использовать встроенную функцию password_hash(), которая автоматически генерирует соль:

php
function makePasswordKey(string $password): string {
return password_hash($password, PASSWORD_BCRYPT, [‘cost’ => 12]);
}

// Проверка пароля
function verifyPassword(string $password, string $hash): bool {
return password_verify($password, $hash);
}

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

## Ручная реализация с солью (для понимания принципа)

Если требуется реализовать функцию вручную (например, для совместимости с legacy-системой):

php
function generateSalt(int $length = 32): string {
return bin2hex(random_bytes($length));
}

function makePasswordKey(string $password, string $salt): string {
return hash(‘sha256’, $salt . $password . $salt);
}

// Сохранение в БД
$salt = generateSalt();
$hash = makePasswordKey($userPassword, $salt);
// Сохраняем $hash и $salt в таблицу users

// Проверка при входе
$storedSalt = /* получить из БД */;
$storedHash = /* получить из БД */;
$inputHash = makePasswordKey($inputPassword, $storedSalt);
if (hash_equals($storedHash, $inputHash)) {
// Пароль верный
}

## Рекомендации по безопасности

1. **Используйте random_bytes()** для генерации соли — это криптографически безопасная функция.
2. **Не используйте MD5/SHA1** без итераций — они слишком быстрые для хэширования паролей.
3. **Применяйте hash_equals()** для сравнения хэшей — защита от timing-атак.
4. **Предпочитайте password_hash()** с алгоритмом PASSWORD_ARGON2ID (PHP 7.3+) для максимальной защиты.
5. **Увеличивайте параметр cost** по мере роста вычислительных мощностей.
6. **Никогда не храните пароль в открытом виде** — только хэш.

## Структура таблицы в БД

sql
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(100) NOT NULL,
password_hash VARCHAR(255) NOT NULL,
— salt хранить отдельно не нужно при использовании password_hash()
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Поле password_hash должно быть VARCHAR(255), так как bcrypt-хэш занимает 60 символов, а Argon2 — больше.

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


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.