Когда я только начинал программировать на PHP, мне казалось, что аутентификация — это что-то сложное и доступное только гуру. Но на самом деле всё проще, чем кажется. В этой статье я покажу, как создать полноценную систему входа на сайт с нуля, без фреймворков и лишних библиотек. Ты научишься хешировать пароли, работать с сессиями и защищать свой код от злоумышленников. Поехали!
Ссылка на оригинальную статьюПочему стоит написать свою систему, а не взять готовую?
Сегодня есть куча готовых решений: Laravel, Symfony, готовые скрипты на GitHub. Но когда ты пишешь сам, ты понимаешь, как всё работает изнутри. Это как собрать велосипед своими руками: ты знаешь каждый винтик и можешь починить его в любой момент. Плюс, своя система легче адаптируется под конкретные задачи.
Но если ты не хочешь изобретать велосипед, можно использовать библиотеки вроде PasswordHash или phpass. Однако для обучения и полного контроля лучше сделать всё самостоятельно.
Основы безопасности: хеширование паролей
Первое, что нужно понять — пароли нельзя хранить в открытом виде. Если база данных утечёт, злоумышленник получит доступ ко всем аккаунтам. Поэтому мы используем хеширование. Хеш — это строка, которая получается из пароля с помощью специального алгоритма. Обратно его расшифровать нельзя.
В PHP есть отличная функция password_hash(). Она автоматически генерирует соль и использует алгоритм bcrypt. Вот как это работает:
$password = 'qwerty123';
$hash = password_hash($password, PASSWORD_DEFAULT);
echo $hash; // $2y$10$...
А для проверки пароля при входе используем password_verify():
if (password_verify($password, $hash)) {
echo 'Пароль верный!';
} else {
echo 'Неверный пароль!';
}
Важно: не используй md5 или sha1 для паролей — они слишком быстрые и легко взламываются. Bcrypt — золотой стандарт.
Создание базы данных и подключение
Для хранения пользователей нам нужна таблица в базе данных. Создадим простую таблицу users с минимальными полями:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Теперь создадим файл db.php для подключения к базе через PDO:
$host = 'localhost';
$dbname = 'myapp';
$user = 'root';
$pass = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Ошибка подключения: ' . $e->getMessage());
}
PDO — это удобный способ работы с БД, он защищает от SQL-инъекций, если использовать подготовленные выражения.
Регистрация пользователя
Теперь напишем обработчик регистрации. Пользователь отправляет данные из формы, мы проверяем их и сохраняем в базу. Не забываем про валидацию.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$email = trim($_POST['email']);
$password = $_POST['password'];
// Простейшая валидация
if (strlen($username) < 3 || strlen($username) > 50) {
$error = 'Имя пользователя должно быть от 3 до 50 символов';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$error = 'Некорректный email';
} elseif (strlen($password) < 6) {
$error = 'Пароль должен быть не менее 6 символов';
} else {
// Проверяем, нет ли уже такого пользователя
$stmt = $pdo->prepare('SELECT id FROM users WHERE username = ? OR email = ?');
$stmt->execute([$username, $email]);
if ($stmt->fetch()) {
$error = 'Пользователь с таким именем или email уже существует';
} else {
// Хешируем пароль и вставляем
$hash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $pdo->prepare('INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?)');
$stmt->execute([$username, $email, $hash]);
header('Location: login.php');
exit;
}
}
}
Обрати внимание: мы используем подготовленные выражения — это защита от SQL-инъекций.
Авторизация и сессии
Теперь самое интересное — вход. После проверки пароля мы сохраняем ID пользователя в сессию. Сессия — это временное хранилище на сервере, которое сохраняется между запросами.
session_start(); // В начале каждого файла, где нужна сессия
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username']);
$password = $_POST['password'];
// Ищем пользователя
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ?');
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password_hash'])) {
// Успешный вход
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
header('Location: profile.php');
exit;
} else {
$error = 'Неверное имя пользователя или пароль';
}
}
Теперь на странице профиля мы можем проверять, авторизован ли пользователь:
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
echo 'Привет, ' . htmlspecialchars($_SESSION['username']);
И не забываем про выход — просто удаляем сессию:
session_start();
session_unset();
session_destroy();
header('Location: login.php');
exit;
Защита от CSRF-атак
CSRF (Cross-Site Request Forgery) — это когда злоумышленник отправляет запрос от имени авторизованного пользователя. Например, можно вставить на стороннем сайте ссылку на смену пароля. Чтобы этого избежать, используем CSRF-токены.
Генерируем токен при создании формы и проверяем его при отправке.
// Генерация токена
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// В форме
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token']; ?>">
// При обработке
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
die('CSRF token mismatch');
}
Это добавляет ещё один слой защиты. Стоит использовать для всех POST-запросов.
Дополнительные советы по безопасности
Вот несколько правил, которые стоит соблюдать:
- Используйте HTTPS — без него вся защита бессмысленна, пароли передаются открыто.
- Установите ограничение на количество попыток входа, чтобы защититься от перебора.
- Регулярно обновляйте PHP и библиотеки.
- Не выводите ошибки на экран в production-режиме.
Для ограничения попыток можно использовать простую логику:
// В таблице users добавить поле failed_attempts и last_attempt_time
// При неудачном входе увеличивать счётчик, при успешном — обнулять
Итоги
Мы создали базовую систему аутентификации на PHP. Она включает регистрацию, вход, выход, защиту паролей и CSRF. Конечно, для продакшена нужно добавить ещё много всего, но база у тебя уже есть.
Главное — помни: безопасность — это не разовая акция, а постоянный процесс. Всегда следи за новыми уязвимостями и улучшай свой код.
Удачи в разработке!



