Как проверить PHP-сайт на уязвимости: пошаговый план
Белая труба с заглушкой на торце и отверстием в боку, из которого выкатывается зелёный шарик

Как проверить PHP-сайт на уязвимости: пошаговый план

Проверка PHP-сайта на уязвимости: сканеры, статический анализ, аудит зависимостей и настроек php.ini. Пошаговый план и чек-лист.

Как проверить сайт на уязвимости PHP

Чтобы проверить PHP-сайт на уязвимости, объедините четыре способа: автоматическое сканирование (OWASP ZAP, Nikto), статический анализ кода (Psalm, Semgrep), аудит зависимостей командой composer audit и ручную проверку настроек php.ini и веб-сервера.

Один инструмент не даёт полной картины: сканер видит сайт снаружи, анализатор читает код изнутри, а аудит конфигурации закрывает то, что не попадает ни в одно из этих полей зрения.

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

Что именно мы ищем

Под проверкой на уязвимости понимают поиск слабых мест, через которые сайт можно взломать, подменить на нём контент или украсть данные. Для PHP-проекта их удобно делить на три слоя: собственный код, сторонние компоненты (CMS, плагины, пакеты Composer) и окружение (версия PHP, настройки сервера, права на файлы).

Каждый слой даёт свою долю проблем. В собственном коде это чаще всего отсутствие проверки входных данных и экранирования вывода. В сторонних компонентах основная опасность в том, что обновления не ставятся месяцами, а уязвимости в популярных плагинах WordPress, модулях Joomla или расширениях 1С-Битрикс публикуются открыто и сразу попадают в арсенал автоматических ботов. В окружении типичны открытые для чтения служебные файлы, включённый вывод ошибок и версии PHP, снятые с поддержки (например, 7.4 и 8.0).

По классификации OWASP Top 10 внедрение вредоносного кода (injection), нарушения контроля доступа и использование устаревших компонентов стабильно входят в число главных рисков для веб-приложений. Именно с них и стоит начинать.

карта рисков

Шесть классов уязвимостей, с которых начинается проверка PHP-сайта

01 / sql-инъекция

В параметр запроса подставляется SQL-код, и атакующий читает или меняет базу данных.

проверка:sqlmap, ZAP, анализ кода

02 / xss

Чужой скрипт выводится на странице без экранирования и выполняется в браузере посетителя.

проверка:ZAP, ручной ввод в формы и параметры

03 / csrf

Запрос выполняется от имени авторизованного пользователя без его ведома.

проверка:токены в формах, атрибут SameSite у cookie

04 / lfi и rfi

Через include или require подключается произвольный файл, имя которого пришло из URL.

проверка:поиск include с переменной, allow_url_include

05 / загрузка файлов

PHP-скрипт загружается под видом картинки и запускается прямо из каталога uploads.

проверка:тип файла, расширение, запрет исполнения

06 / устаревший код

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

проверка:composer audit, список обновлений CMS

Как понять, что с сайтом уже что-то не так

Иногда проверку запускают не по плану, а после тревожных симптомов. К ним относятся незнакомые файлы в каталогах uploads, cache и tmp, внезапные редиректы на сторонние ресурсы (часто только для посетителей, пришедших из поиска), резкий рост нагрузки на хостинг, всплеск исходящей почты и жалобы пользователей на всплывающие окна.

Второй источник сигналов — сами поисковики. В Яндекс Вебмастере есть раздел «Безопасность и нарушения», а в Google Search Console — отчёт «Проблемы безопасности». Если там появилось предупреждение о вредоносном коде или взломе, сайт уже попал в зону риска: в выдаче может появиться пометка об опасности, а позиции начнут падать.

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

Пошаговый план проверки PHP-сайта на уязвимости

  1. 01

    Подготовьте тестовую среду: сделайте полную резервную копию файлов и базы данных и разверните копию сайта на отдельном поддомене или локально. Активные сканеры шлют сотни запросов и могут изменить данные, поэтому боевой сайт для этого не подходит.

  2. 02

    Проверьте версии и зависимости: узнайте версии PHP, CMS и плагинов, выполните composer audit (доступна в Composer 2.4 и новее), сверьте список обновлений. Всё, что не получает патчи безопасности, кандидат на замену или обновление.

  3. 03

    Запустите автоматический сканер: OWASP ZAP в режиме baseline или полного сканирования и Nikto для проверки веб-сервера. Сохраните отчёты и отсортируйте находки по критичности.

  4. 04

    Проведите статический анализ кода: Psalm с анализом заражённых данных (taint analysis), Semgrep с правилами для PHP и PHPStan на высоком уровне строгости. Они находят места, где пользовательские данные попадают в SQL-запрос, вывод или файловую функцию без обработки.

  5. 05

    Проверьте вручную точки входа: все формы, параметры GET и POST, cookie, заголовки, загрузку файлов, API-эндпоинты. Попробуйте ввести одинарную кавычку, тег script и путь вида ../../ и посмотрите, как реагирует приложение.

  6. 06

    Проверьте конфигурацию: директивы php.ini, права на файлы (обычно 644 для файлов и 755 для каталогов), доступность служебных файлов .env, .git, резервных копий и дампов базы по прямым URL, наличие HTTPS и защитных заголовков.

  7. 07

    Поищите следы взлома: найдите недавно изменённые файлы (например, командой find с параметром -mtime), проверьте код на конструкции eval, base64_decode, gzinflate и preg_replace с модификатором e, просмотрите журналы доступа на подозрительные запросы.

  8. 08

    Сверьтесь с поисковиками: откройте Яндекс Вебмастер и Google Search Console, проверьте разделы о безопасности и нарушениях, а также индексацию — нет ли в ней незнакомых спамных страниц.

  9. 09

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

Динамический и статический подход: в чём разница

Два главных метода проверки дополняют друг друга. Динамическое тестирование (DAST) работает как внешний атакующий: сканер не видит исходный код, а только отправляет запросы и анализирует ответы. Так находят проблемы, которые реально проявляются на работающем сайте, например отражённый XSS или открытые служебные файлы.

Статический анализ (SAST) читает исходный код без запуска и отслеживает путь данных от ввода до опасной функции. Он находит уязвимости в редко используемых ветках кода, куда сканер просто не дойдёт, но даёт больше ложных срабатываний.

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

ИнструментЧто проверяетКогда применять
OWASP ZAPВеб-приложение снаружи: XSS, инъекции, небезопасные заголовки, cookieПеред релизом и после крупных изменений
NiktoВеб-сервер: устаревшее ПО, опасные файлы, небезопасная конфигурацияПри первичном аудите и смене хостинга
sqlmapПодверженность параметров SQL-инъекциямДля подтверждения найденной проблемы на тестовой копии
Psalm (taint analysis)Путь пользовательских данных к SQL, выводу и файловым функциямВ процессе разработки и при код-ревью
SemgrepОпасные шаблоны в коде по наборам правилВ автоматической проверке при каждой сборке
composer auditИзвестные уязвимости в пакетах ComposerПеред каждым обновлением и по расписанию
Яндекс Вебмастер и Google Search ConsoleСообщения о вирусах, взломе и подозрительных страницахПостоянно, как система раннего оповещения
Сканируйте только собственные сайты или проекты, на проверку которых есть письменное разрешение владельца. Несанкционированное тестирование чужого ресурса может быть расценено как неправомерный доступ к компьютерной информации (ст. 272 УК РФ). Даже на своём сайте запускайте активные сканеры на тестовой копии, а не на боевой версии.

Что делать с найденными проблемами

Отчёт сканера — это только начало. Большинство критичных уязвимостей в PHP закрываются четырьмя базовыми приёмами. Первый — подготовленные запросы (PDO или mysqli с параметрами) вместо склейки SQL-строк. Второй — экранирование вывода через htmlspecialchars с явной кодировкой во всех местах, где данные пользователя попадают в HTML. Третий — CSRF-токены во всех формах, которые что-то меняют, и атрибут SameSite у cookie. Четвёртый — строгая проверка загружаемых файлов: белый список расширений, проверка реального типа содержимого, случайные имена и запрет исполнения скриптов в каталоге загрузок.

Ниже наглядный пример: типичный уязвимый фрагмент и его безопасный вариант.

было / стало

Один и тот же код до и после исправления

было: уязвимо
$id = $_GET['id'];
$res = $db->query(
  'SELECT * FROM users WHERE id = ' . $id
);

echo 'Привет, ' . $_GET['name'];
  • Параметр id идёт прямо в SQL: возможна инъекция
  • Имя выводится без экранирования: возможен XSS
стало: безопасно
$stmt = $pdo->prepare(
  'SELECT * FROM users WHERE id = :id'
);
$stmt->execute(['id' => (int) $_GET['id']]);

echo 'Привет, ' . htmlspecialchars(
  $_GET['name'], ENT_QUOTES, 'UTF-8'
);
  • Данные передаются параметром, а не частью запроса
  • Вывод экранирован, скрипт превратится в обычный текст

Обратите внимание на деталь: приведение (int) для идентификатора тоже полезно, но главную защиту даёт именно подготовленный запрос. Валидация типа и экранирование работают как дополнительные слои, а не как замена друг другу.

Если сайт построен на фреймворке (Laravel, Symfony, Yii) или CMS, значительная часть защиты уже встроена: ORM, шаблонизатор с автоматическим экранированием, CSRF-механизмы. Уязвимости появляются там, где разработчик обходит эти механизмы: пишет сырые SQL-запросы, выводит данные в обход шаблонизатора или отключает проверку токена ради «удобства».

Типичные ошибки при проверке PHP-сайта

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

Как делают неправильно

  • Запускают активный сканер сразу на боевом сайте и получают сбои или испорченные данные
  • Ограничиваются одним сканером и считают, что проблем нет
  • Игнорируют сторонние плагины и считают, что уязвим только собственный код
  • Закрывают уязвимость в одном месте, но не ищут такой же шаблон в остальном коде
  • Не перепроверяют сайт после исправлений

Как правильно

  1. 01

    Тестируйте на копии сайта с отдельной базой данных

  2. 02

    Комбинируйте сканер, статический анализ, аудит зависимостей и ручную проверку

  3. 03

    Включайте в аудит все плагины, темы и пакеты Composer, включая неиспользуемые

  4. 04

    После исправления ищите по всему проекту аналогичные конструкции

  5. 05

    Повторяйте сканирование после каждой серии исправлений и сохраняйте отчёты для сравнения

Конфигурация: то, что часто упускают

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

Поэтому отдельно проверьте, что по прямым адресам недоступны файлы .env, .git, composer.json с lock-файлом, дампы базы данных (.sql), архивы (.zip, .tar.gz), а также служебные скрипты вроде phpinfo.php и тестовые страницы. Закройте листинг каталогов и убедитесь, что сайт работает по HTTPS с корректными защитными заголовками.

Ниже собран короткий чек-лист ключевых директив php.ini, которые стоит проверить в первую очередь.

чек-лист php.ini

Семь настроек, которые закрывают типовые дыры

display_errorsOffПосетитель не видит пути к файлам и тексты ошибок
expose_phpOffВерсия PHP не передаётся в заголовках ответа
allow_url_includeOffЗакрыто удалённое подключение файлов (RFI)
session.cookie_httponly1Cookie сессии недоступна для JavaScript, риск кражи при XSS ниже
session.cookie_secure1Cookie сессии передаётся только по HTTPS
session.use_strict_mode1Сервер не принимает идентификатор сессии, который сам не создавал
disable_functionsсписокОтключите exec, shell_exec, system, passthru, если они не нужны проекту

Как часто проверять и как встроить это в работу

Одноразовый аудит быстро устаревает: появляются новые версии библиотек, новые найденные уязвимости и новый код. Разумный минимум — проверка раз в квартал, а также перед каждым крупным релизом, после обновления CMS и после установки нового плагина.

Если у проекта есть разработчики, автоматизируйте то, что поддаётся автоматизации. Запуск composer audit, Semgrep и статического анализатора можно включить в процесс сборки, чтобы код с известной уязвимостью не попадал на боевой сервер. Ежедневный взгляд в Яндекс Вебмастер и Google Search Console занимает пару минут, но позволяет быстро заметить предупреждения о безопасности.

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

Что даёт регулярная проверка на уязвимости

  1. 01

    Защита данных клиентов, заказов и учётных записей от утечек

  2. 02

    Сохранение позиций в Яндексе и Google: сайт без вредоносного кода не получает пометок об опасности и санкций

  3. 03

    Экономия на восстановлении: найти дыру дешевле, чем чистить взломанный сайт и объясняться с клиентами

  4. 04

    Соответствие требованиям закона о защите персональных данных (152-ФЗ) при работе с формами и личными кабинетами

  5. 05

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

Итоги: безопасность PHP-сайта — это процесс, а не разовая акция

Надёжная проверка PHP-сайта на уязвимости складывается из четырёх частей: сканер, анализ кода, аудит зависимостей и проверка конфигурации.
  1. 01

    Подготовьте тестовую копию и резервные копии, прежде чем запускать активные сканеры

  2. 02

    Используйте связку OWASP ZAP, Nikto, Psalm или Semgrep и composer audit вместо одного инструмента

  3. 03

    Закрывайте типовые дыры: подготовленные запросы, экранирование вывода, CSRF-токены, проверка загрузки файлов

  4. 04

    Следите за разделами безопасности в Яндекс Вебмастере и Google Search Console и повторяйте проверку регулярно

Начните с самого простого: обновите PHP, CMS и плагины, выполните composer audit и посмотрите отчёты безопасности в Вебмастере и Search Console. Уже это закроет значительную часть известных рисков. Если сайт обрабатывает платежи или персональные данные, доверьте глубокий аудит специалистам: свежий взгляд почти всегда находит то, что давно примелькалось команде проекта.

Часто задаваемые вопросы

Подозреваете дыры в PHP-коде? Проведём аудит безопасности вашего сайта

Найдём уязвимости в коде, плагинах и настройках сервера и дадим понятный план исправлений

Бесплатная предварительная оценкаОтчёт за 3 дняБез остановки сайта

Проверено на сотнях PHP-проектов

Политика конфиденциальности

При оставлении заявки на ресурсе «https://gurucontext.ru» пользователи предоставляют следующие сведения:

  • Имя
  • Контактный телефон или Telegram
  • Адрес сайта пользователя (не обязательно)

Также администрация сайта получает данные об IP-адресе посетителей, типе браузера, времени нахождения на сайте и прочие подобные сведения через сервисы статистики.

Использование информации

Вся полученная информация используется администрацией «https://gurucontext.ru» исключительно в целях связи с клиентом.

Защита персональных данных

Компания «https://gurucontext.ru» обязуется не разглашать сведения, полученные от пользователей, и хранит их в защищённом виде.

Предоставление данных третьим лицам

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

Контакты

Телефон: +7 (499) 955-47-00.
E-mail: info@gurucontext.ru.