Хеширование
Хеширование — это как надежный сейф для паролей. Оно работает в одну сторону: вы превращаете пароль в набор символов, который невозможно превратить обратно в исходный пароль.
Imhotep предлагает три алгоритма хеширования:
Bcrypt — проверенный временем алгоритм, подходит для большинства проектов.
Argon — современный алгоритм, устойчив к атакам через кэш-память.
Argon2id — гибридный вариант, сочетает защиту от двух типов атак.
Конфигурирование
Настройки хеширования находятся в файле config/hash.php. Изучите содержимое файла.
Настройка сложности Bcrypt
Параметр cost (или rounds — поддерживаются оба названия) определяет, сколько времени займет хеширование. Чем выше число, тем безопаснее, но и медленнее.
// Оба варианта работают одинаково
$hash = Hash::make('password', [
'cost' => 12,
]);
$hash = Hash::make('password', [
'rounds' => 12, // Тоже работает!
]);
Совет: Не ставьте
costслишком высоким без необходимости. Если хеширование одного пароля занимает около 1 секунды, при 1000 регистраций в час ваша база данных может захлебнуться. Начните с 10, тестируйте производительность и постепенно повышайте.
Ограничение длины пароля для Bcrypt
Bcrypt имеет фундаментальное ограничение — он хеширует только первые 72 байта пароля, остальная часть игнорируется. Чтобы избежать этой ситуации, вы можете включить проверку длины:
// В config/hash.php
'bcrypt' => [
'cost' => 12,
'limit' => 72, // Максимальная длина пароля
],
Если пароль превышает указанный лимит, Hash::make(...) выбросит исключение:
use Imhotep\Facades\Hash;
use InvalidArgumentException;
try {
$hash = Hash::make(str_repeat('a', 100));
} catch (InvalidArgumentException $e) {
echo "Пароль слишком длинный: " . $e->getMessage();
// Value is too long to hash. Value must be less than 72 bytes.
}
Важно: Ограничение в 72 байта — это особенность алгоритма Bcrypt. Проверка длины добавляет дополнительный уровень безопасности, но не обязательна. Вы можете отключить её, установив
limitвnull.
Настройка сложности Argon2
Argon2 дает больше гибкости — вы управляете тремя параметрами:
$hash = Hash::make('password', [
'memory' => 2048, // Сколько памяти (в КБ) использует алгоритм
'time' => 4, // Сколько итераций (время)
'threads' => 2, // Сколько потоков использовать
]);
- memory: Чем больше памяти, тем сложнее взломать хеш с помощью специальных аппаратных ускорителей.
- time: Чем больше итераций, тем дольше вычисляется хеш (и тем сложнее перебор).
- threads: Количество потоков — влияет на скорость вычислений.
Хеширование паролей
Самый простой способ захешировать пароль — использовать фасад Hash:
namespace App\Controllers;
use App\Models\User;
use Imhotep\Http\Request;
use Imhotep\Facades\Hash;
class UserController
{
public function register(Request $request)
{
$password = $request->post('password');
// Хешируем пароль — теперь его можно безопасно хранить в базе
$hashedPassword = Hash::make($password);
// Сохраняем в базу...
User::create([
'password' => $hashedPassword
]);
return response()->json(['message' => 'Пользователь создан']);
}
}
Проверка пароля
Когда пользователь входит в систему, вы не "расшифровываете" хеш — вы проверяете, совпадает ли введенный пароль с сохраненным хешем:
namespace App\Controllers;
use App\Models\User;
use Imhotep\Http\Request;
use Imhotep\Facades\Hash;
class AuthController
{
public function login(Request $request)
{
$email = $request->post('email');
$password = $request->post('password');
// Ищем пользователя
$user = User::where('email', $email)->first();
if (!$user) {
return response()->json(['error' => 'Пользователь не найден'], 404);
}
// Проверяем пароль
if (Hash::check($password, $user->password)) {
// Пароль верный — пускаем пользователя
return response()->json(['message' => 'Добро пожаловать!']);
}
return response()->json(['error' => 'Неверный пароль'], 401);
}
}
Важно:
Hash::checkавтоматически определяет, каким алгоритмом был создан хеш, и применяет соответствующую проверку. Вам не нужно указывать алгоритм — система сама разберется.
Обновление устаревших хешей
Представьте, вы повысили cost с 10 до 12. Все новые пароли будут хешироваться с cost: 12, но старые остались с cost: 10. Это нормально, но менее безопасно.
Метод needsRehash поможет определить, пора ли обновить хеш:
namespace App\Controllers;
use Imhotep\Facades\Hash;
class AuthController
{
public function login(Request $request)
{
// ... нашли пользователя, проверили пароль ...
if (Hash::check($password, $user->password)) {
// Проверяем, не устарел ли хеш
if (Hash::needsRehash($user->password)) {
// Обновляем хеш на новый (с актуальными настройками)
$user->password = Hash::make($password);
User::update($user);
// Пользователь даже не заметит — он просто вошел
}
// Пускаем пользователя
return response()->json(['message' => 'Добро пожаловать!']);
}
}
}
Проверка алгоритма хеширования
Imhotep по умолчанию проверяет, что хеш создан с помощью того алгоритма, который указан в вашем приложении. Это дополнительный уровень безопасности.
// Если ваш драйвер — 'bcrypt'
// Но кто-то подсунул хеш, созданный через 'argon'
// Imhotep выбросит исключение
use Imhotep\Facades\Log;
use Imhotep\Facades\Hash;
try {
$isValid = Hash::check($password, $hashFromDatabase);
} catch (RuntimeException $e) {
// "This password does not use the bcrypt algorithm."
// Возможно, атака!
Log::warning('Подозрительный хеш: алгоритм не соответствует', [
'hash' => $hashFromDatabase
]);
}
Если вы мигрируете с одного алгоритма на другой (например, с Bcrypt на Argon2id), эта проверка будет мешать. Отключите её в .env:
HASH_VERIFY=false
После завершения миграции не забудьте включить обратно.