Базовая проверка безопасности PHP-сайта

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

Доступы и пароли

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

  • удалить неактуальные учётные записи;
  • заменить общие пароли на персональные доступы;
  • включить двухфакторную защиту там, где она есть;
  • не хранить пароли в репозитории;
  • разделить доступы к production и test.

В проекте на Yii2 локальные параметры обычно лежат в config/params-local.php или похожих файлах. Такие файлы не должны попадать в git.

git status
git grep "password"
git grep "secret"

Права на файлы и директории

Права 777 часто ставят “чтобы заработало”. Временно это действительно может помочь, но на рабочем сайте лучше настроить владельца и группы нормально. На запись обычно нужны runtime, web/assets и директории загрузок.

find . -type d -perm 0777
find . -type f -perm 0777

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

Загрузка файлов

Формы загрузки — одно из первых мест, которое нужно проверить. Нельзя доверять только расширению файла из имени. Нужно проверять MIME-тип, размер, расширение, а загруженные файлы лучше хранить так, чтобы они не выполнялись как PHP.

$file = UploadedFile::getInstance($model, 'file');

if ($file && !in_array($file->extension, ['jpg', 'jpeg', 'png', 'webp'], true)) {
    throw new BadRequestHttpException('Недопустимый тип файла');
}

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

location /uploads/ {
    location ~ \.php$ {
        deny all;
    }
}

Формы и CSRF

В Yii2 CSRF-защита обычно включена по умолчанию. Проблемы начинаются, когда её отключают для быстрого исправления AJAX-формы и забывают вернуть. Отключение CSRF должно быть редким исключением, а не стандартным решением.

public $enableCsrfValidation = true;

Для AJAX-запросов лучше корректно передавать CSRF-токен, а не выключать проверку целиком.

<meta name="csrf-token" content="<?= Yii::$app->request->csrfToken ?>">

SQL и ActiveRecord

Даже если проект использует ActiveRecord, в старом коде могут оставаться ручные SQL-строки. Опасное место — подстановка данных пользователя прямо в запрос.

// плохо
$sql = "SELECT * FROM users WHERE email = '" . $_GET['email'] . "'";

Нормальный вариант — параметры:

$user = Yii::$app->db->createCommand(
    'SELECT * FROM users WHERE email = :email',
    [':email' => $email]
)->queryOne();

Админка и служебные разделы

Админка не должна быть доступна без авторизации, а старые служебные файлы лучше удалить. На проектах после переездов часто остаются backup.zip, old.php, test.php, phpinfo.php и временные дампы базы.

find web -iname "*backup*"
find web -iname "*old*"
find web -iname "phpinfo.php"
find web -iname "*.sql"
find web -iname "*.zip"

Если такие файлы нужны для истории, им не место в публичной директории сайта.

Обновления зависимостей

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

composer outdated
composer audit

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

Резервные копии

Без резервных копий безопасность неполная. Важно не только создавать бэкапы, но и проверять восстановление. Архив, который никогда не пробовали развернуть, даёт ложное спокойствие.

  • бэкап базы выполняется регулярно;
  • файлы загрузок сохраняются отдельно;
  • копии не лежат только на том же сервере;
  • проверено восстановление на тестовом окружении;
  • старые копии удаляются по понятному правилу.

Короткий чек-лист

  1. Проверить актуальные доступы.
  2. Убрать секреты из репозитория.
  3. Проверить права 777.
  4. Запретить выполнение PHP в uploads.
  5. Проверить CSRF на формах.
  6. Найти ручные SQL-запросы с подстановкой строк.
  7. Удалить временные файлы из web.
  8. Проверить composer audit.
  9. Проверить наличие и восстановление бэкапов.

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

Комментарии (0)

Пока нет комментариев. Будьте первым!