
Аудит PHP-кода: чек-лист, этапы и инструменты
Аудит PHP-кода — это проверка проекта на уязвимости, ошибки, медленные места и технический долг. Разбираем этапы, инструменты и типичные ошибки.
Аудит PHP-кода: как найти уязвимости и технический долг до того, как они выстрелят
Аудит PHP-кода — это комплексная проверка проекта на уязвимости, ошибки, узкие места производительности и технический долг. Её проводят с помощью статических анализаторов (PHPStan, Psalm, SonarQube) и ручного ревью, а результатом становится отчёт с приоритизированным списком исправлений.
PHP до сих пор работает на огромной доле сайтов, интернет-магазинов и корпоративных систем. Многие из них живут по 7–10 лет, переходили от одного подрядчика к другому и обросли «временными» решениями, которые стали постоянными. В этой статье разберём, что именно входит в аудит, какие инструменты использовать, как выстроить процесс по шагам и какие ошибки чаще всего портят результат.
Что такое аудит PHP-кода и чем он отличается от обычного code review
Code review — это ежедневная практика: коллега просматривает небольшой набор изменений перед слиянием в основную ветку. Он отвечает на вопрос «хороша ли эта правка?». Аудит решает другую задачу: он оценивает весь проект целиком — кодовую базу, зависимости, конфигурацию сервера, процессы разработки и развёртывания.
По сути, аудит — это диагностика. Вы получаете независимую оценку состояния системы и понимаете, где риски, а где всё в порядке. Именно поэтому аудит чаще всего заказывают в ключевые моменты жизни проекта: при покупке или передаче сайта, смене подрядчика, подготовке к масштабированию, миграции на новую версию PHP или после взлома.
Важно, что аудит не сводится к «найти баги». Хороший аудитор оценивает также читаемость и предсказуемость кода: насколько легко новому разработчику войти в проект, сколько времени уходит на типовую доработку и насколько безопасно вносить изменения без риска что-то сломать.
Когда аудит PHP-кода действительно необходим
- 01
Проект достался вам от другой команды или подрядчика, и никто не знает, что внутри
- 02
Сайт был взломан, заражён вирусом или попал в список небезопасных у Яндекса или Google
- 03
Страницы стали загружаться заметно медленнее, а нагрузка на сервер растёт быстрее, чем трафик
- 04
Любая небольшая правка ломает несвязанные части системы, а разработка замедляется
- 05
Планируется переход с PHP 7.x на 8.x или смена фреймворка (например, с самописной CMS на Laravel или Symfony)
- 06
Нужно подтвердить безопасность перед сертификацией, интеграцией с банком или сделкой по продаже бизнеса
- 07
Перед запуском крупной рекламной кампании в Яндекс Директ и Google Ads, когда простой сайта означает прямые потери бюджета
Четыре направления проверки
Чтобы аудит не превратился в хаотичное чтение файлов, его принято разбивать на несколько осей. Каждая из них отвечает на свой вопрос и использует свой набор методов. Ниже — схема, по которой работает большинство команд.
Важно сразу договориться, какие направления входят в задачу. Если вам нужен только быстрый «срез безопасности» перед релизом, глубокий анализ архитектуры будет лишним. А если вы готовите проект к масштабированию, одной проверки на уязвимости совершенно недостаточно.
Уязвимости
SQL-инъекции, XSS, CSRF, небезопасная загрузка файлов, хранение паролей и секретов, права доступа.
Код и архитектура
Типизация, дублирование, цикломатическая сложность, связность модулей, соблюдение PSR.
Производительность
N+1 запросы, индексы БД, OPcache, кеширование, медленные участки в профайлере.
Зависимости и процессы
Версия PHP, пакеты Composer с уязвимостями, тесты, CI/CD, логирование, резервные копии.
Безопасность: с чего начинать
Если времени мало, начинайте именно с безопасности: последствия уязвимостей самые тяжёлые — утечка клиентской базы, подмена содержимого страниц, рассылка спама с вашего сервера, блокировка хостером.
В PHP-проектах чаще всего встречаются одни и те же проблемы. SQL-инъекции — запросы, собранные конкатенацией строк с данными из `$_GET` и `$_POST`. XSS — вывод пользовательских данных без `htmlspecialchars` или экранирования в шаблонизаторе. CSRF — формы и AJAX-запросы без проверки токена. Небезопасная загрузка файлов — проверка только по расширению, а не по содержимому, и сохранение в публичную папку с возможностью выполнения. Опасные функции — `eval`, `unserialize` на пользовательских данных, `include` с переменным путём.
Отдельно проверяют работу с паролями (должны использоваться `password_hash` и `password_verify`, а не MD5 или SHA1), настройки сессий (флаги `HttpOnly`, `Secure`, `SameSite`), отключённый `display_errors` на продакшене и отсутствие файлов `.env`, дампов базы и резервных копий в публичной директории.
Ниже — самый показательный пример из практики аудитов: типовая SQL-инъекция и её исправление.
$sql = 'SELECT * FROM users WHERE id = '
. $_GET['id'];
$res = $pdo->query($sql);Параметр попадает в запрос как есть. Значение вида1 OR 1=1вернёт всех пользователей, а более сложный payload позволит читать и менять данные.
$stmt = $pdo->prepare(
'SELECT id, name FROM users WHERE id = :id'
);
$stmt->execute(['id' => (int) $_GET['id']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);Подготовленный запрос отделяет код SQL от данных, а явное приведение типа и выборка нужных полей снижают риски и нагрузку.
Качество кода и архитектура
Даже полностью безопасный код может быть «дорогим» в поддержке. Поэтому вторая часть аудита — оценка того, насколько проект поддаётся развитию. Здесь смотрят на несколько признаков.
Первый — размер и ответственность классов и функций. Файлы на 3 000 строк, контроллеры, в которых смешаны SQL-запросы, бизнес-логика и вёрстка, — классический сигнал, что любая правка будет рискованной. Второй — дублирование: одна и та же логика расчёта цены, скопированная в пять мест, гарантирует, что в шестом месте про неё забудут. Третий — типизация: наличие декларации `declare(strict_types=1)`, типов аргументов и возвращаемых значений, которые доступны начиная с PHP 7 и существенно расширены в PHP 8.
Четвёртый — соответствие стандартам PSR (PSR-1, PSR-4, PSR-12): автозагрузка через Composer вместо россыпи `require_once`, единый стиль, понятные пространства имён. Пятый — тесты. Не обязательно стопроцентное покрытие, но критичные сценарии (оплата, регистрация, расчёты) должны быть защищены автоматическими проверками, иначе обновление PHP или библиотек превращается в лотерею.
Для большинства из этих проверок существуют готовые инструменты, которые легко встроить в рабочий процесс.
| Задача | Инструменты | Что показывают |
|---|---|---|
| Анализ типов и поиск ошибок без запуска | PHPStan, Psalm | Обращения к несуществующим методам, неверные типы, недостижимый код |
| Стиль кода и соответствие PSR-12 | PHP_CodeSniffer, PHP CS Fixer | Нарушения форматирования, которые можно исправить автоматически |
| Сложность и дублирование | PHPMD, PHPMetrics | Функции с высокой цикломатической сложностью, раздутые классы |
| Уязвимости в зависимостях | composer audit, Roave Security Advisories | Пакеты с известными CVE и рекомендуемые версии для обновления |
| Поиск небезопасных паттернов | Semgrep, SonarQube | Конкатенацию в SQL, использование eval и опасных функций |
| Профилирование производительности | Xdebug, Blackfire, XHProf | Самые медленные функции, тяжёлые запросы, потребление памяти |
| Тесты и их качество | PHPUnit, Infection | Покрытие кода и «слабые» тесты, которые не ловят ошибки |
Автоматика даёт основу, но не заменяет голову
Запуск инструментов — это быстрая и недорогая часть аудита, которая выявляет «низко висящие плоды». Например, PHPStan на высоком уровне строгости на старом проекте легко выдаст тысячи замечаний. Это нормально: главное — не пытаться исправить всё сразу, а зафиксировать текущее состояние (baseline) и не допускать появления новых ошибок.
Однако у автоматики есть слепые зоны. Анализатор не поймёт, что скидка применяется дважды, что у менеджера есть доступ к чужим заказам по прямой ссылке (IDOR) или что API возвращает лишние поля с персональными данными. Такие вещи находят только при ручном просмотре ключевых сценариев: авторизации, оплаты, личного кабинета, административной панели.
Поэтому рабочая схема выглядит так: сначала автоматические инструменты снимают шум, затем аудитор концентрируется на критичных модулях и бизнес-логике. Ниже — последовательность шагов, которой удобно придерживаться.
Как провести аудит PHP-кода шаг за шагом
- 01
Определите цели и границы. Зафиксируйте, что проверяете (весь проект или отдельные модули), что для вас приоритет — безопасность, скорость или поддерживаемость, и какие данные нужны для оценки (репозиторий, доступ к тестовому серверу, логи).
- 02
Соберите инвентарь проекта. Выпишите версию PHP, фреймворк или CMS, список пакетов из composer.json и composer.lock, используемые расширения, базу данных, очереди, кеш и внешние интеграции.
- 03
Запустите автоматические проверки. Выполните composer audit, PHPStan или Psalm, PHP_CodeSniffer, PHPMD и сканер безопасности вроде Semgrep. Сохраните результаты как отправную точку.
- 04
Проверьте конфигурацию окружения. Изучите php.ini (display_errors, expose_php, open_basedir), права на файлы и папки, настройки веб-сервера, наличие HTTPS, заголовков безопасности и закрытость служебных файлов.
- 05
Выполните ручное ревью критичных участков. Разберите авторизацию и роли, работу с платежами, загрузку файлов, формы, API-эндпоинты и места, где используются данные пользователя.
- 06
Профилируйте производительность. Включите slow query log в базе, снимите профиль в Xdebug, Blackfire или XHProf на типовых сценариях, найдите N+1 запросы, отсутствующие индексы и места без кеширования.
- 07
Оцените риски и приоритеты. Для каждой находки определите серьёзность (критическая, высокая, средняя, низкая), вероятность эксплуатации и трудоёмкость исправления.
- 08
Подготовьте отчёт и план исправлений. Опишите проблему, где она найдена, чем опасна, как воспроизвести и как исправить. После правок проведите повторную проверку, чтобы убедиться, что уязвимости закрыты.
Производительность и связь с SEO
Скорость — тема, которая интересует не только разработчиков, но и маркетологов. Медленный ответ сервера (высокий TTFB), долгая генерация страницы и ошибки 5xx напрямую влияют на поведение пользователей и на то, как поисковые системы обходят сайт. И Яндекс, и Google учитывают скорость и стабильность при оценке качества ресурса, а роботы могут сокращать частоту обхода, если сервер отвечает медленно или нестабильно.
Типичные причины тормозов в PHP-проектах — N+1 запросы (когда для каждой строки списка выполняется отдельный запрос), отсутствие индексов на полях фильтрации и сортировки, выборка `SELECT *` там, где нужны два поля, отключённый или неверно настроенный OPcache, отсутствие кеширования результатов тяжёлых вычислений в Redis или Memcached, а также синхронная отправка писем и обращений к внешним API прямо в момент запроса пользователя.
После исправлений полезно сравнить показатели «до» и «после»: время ответа, количество запросов к базе, пиковое потребление памяти. Динамику сайта в целом удобно отслеживать в Яндекс Метрике и Google Analytics, а технические ошибки обхода — в Яндекс Вебмастере и Google Search Console.
Исправить немедленно
Работающая SQL-инъекция, доступ к админке без пароля, открытые дампы БД, утёкшие ключи. Срок — от часов до 1–2 дней.
В ближайший спринт
XSS в формах, отсутствие CSRF-токенов, пакеты с известными CVE, устаревшая версия PHP без патчей безопасности.
Запланировать в квартале
N+1 запросы, отсутствие индексов, дублирование логики, слабое логирование и нехватка тестов в критичных модулях.
Решать по мере работы
Нарушения стиля, неиспользуемый код, устаревшие комментарии. Автоматизируйте через PHP CS Fixer и Rector.
Отчёт, который можно превратить в работу
Результат аудита ценен ровно настолько, насколько по нему можно действовать. Отчёт на 80 страниц без приоритетов обычно остаётся лежать в папке. Хороший документ состоит из краткого резюме для руководителя (общий уровень риска, три-пять главных проблем и оценка трудозатрат) и детальной части для разработчиков.
Для каждой находки полезно указывать: что обнаружено, где (файл и строка), чем опасно, как воспроизвести и как исправить с примером кода. Дополнительно стоит приложить дорожную карту: что делаем сразу, что в ближайший месяц, что в долгосрочной перспективе. Так бизнес видит не просто список проблем, а понятный бюджет и сроки.
Наконец, договоритесь о повторной проверке. Аудит без верификации исправлений оставляет ощущение безопасности, которого на самом деле нет: часть правок делают частично или с новыми ошибками.
Частые ошибки при аудите PHP-кода
Как делать не стоит
- Ограничиться запуском одного анализатора и считать аудит законченным
- Проверять код только на тестовых данных, не глядя на настройки продакшена
- Пытаться исправить все замечания PHPStan за один раз и остановить развитие продукта
- Игнорировать зависимости: уязвимый пакет в vendor опаснее собственной небрежной функции
- Поручать аудит автору кода, у которого «замылен» взгляд
- Не фиксировать результаты и не проверять, что исправления действительно закрыли проблемы
Как правильно
- 01
Сочетать статический анализ, проверку конфигурации и ручное ревью критичных сценариев
- 02
Сверять код с реальным окружением: версия PHP, расширения, права, переменные окружения
- 03
Использовать baseline и повышать строгость анализатора постепенно, уровень за уровнем
- 04
Включить composer audit в CI и обновлять пакеты регулярно, а не раз в три года
- 05
Привлекать независимого специалиста или хотя бы коллегу из другой команды
- 06
Вести журнал находок, назначать ответственных и проводить повторную проверку после правок
Внутренний аудит или внешний подрядчик: что выбрать
Внутренний аудит дешевле и быстрее запускается: команда знает проект, контекст и бизнес-логику. Но у него есть ограничения — «замыленность» взгляда, нехватка опыта в пентесте и естественное желание не выносить сор из избы.
Внешний аудитор смотрит на систему свежим взглядом, знает типичные паттерны взлома, имеет готовые чек-листы и не зависит от внутренней политики. Это особенно важно для проектов с платёжными данными, персональной информацией и высокой ценой простоя.
Оптимальный вариант для большинства компаний — гибрид: регулярные автоматические проверки и внутреннее ревью в повседневной работе плюс независимый комплексный аудит раз в год или перед значимыми изменениями.
Итоги: как сделать аудит PHP-кода полезным
- 01
Определите цели: безопасность, производительность, поддерживаемость или всё вместе
- 02
Сочетайте автоматические инструменты (PHPStan, Psalm, composer audit, Semgrep) с ручным ревью критичных модулей
- 03
Приоритизируйте находки по серьёзности и срокам, а не пытайтесь исправить всё сразу
- 04
Фиксируйте результаты в отчёте с примерами исправлений и планом работ
- 05
Встройте проверки в CI и повторяйте полноценный аудит не реже раза в год
Системная проверка кода снижает риск взлома, ускоряет сайт, облегчает передачу проекта новой команде и делает разработку предсказуемой. Если вы не уверены, в каком состоянии ваш PHP-проект, лучше узнать об этом на этапе аудита, а не из письма от хостера или из падения конверсии.
Часто задаваемые вопросы
Небольшой проект до 20–30 тысяч строк обычно проверяют за 3–5 рабочих дней. Крупный монолит с устаревшим фреймворком и множеством интеграций может занять две-четыре недели. Срок зависит от объёма кода, наличия тестов и глубины проверки: только безопасность или ещё и архитектура с производительностью.
Статический анализ (PHPStan, Psalm, SonarQube) автоматически находит типовые ошибки, неопределённые переменные, несовместимые типы и известные небезопасные паттерны. Ручное ревью выявляет то, что инструменты не видят: ошибки бизнес-логики, слабую архитектуру, обходные пути в авторизации. Надёжный аудит всегда сочетает оба подхода.
Полный аудит стоит проводить минимум раз в год, а также перед крупным релизом, сменой команды, обновлением версии PHP или фреймворка и после инцидента безопасности. Автоматические проверки (анализатор, composer audit) лучше встроить в CI и запускать при каждом коммите.
Косвенно — да. Медленные запросы к базе, отсутствие кеширования и ошибки сервера ухудшают скорость загрузки и стабильность сайта, а эти факторы учитывают и Яндекс, и Google. Взломанный сайт может попасть в список небезопасных, что сильно бьёт по трафику. Состояние можно отслеживать в Яндекс Вебмастере и Google Search Console.
Базовую проверку можно сделать своими силами: запустить PHPStan, PHP_CodeSniffer и composer audit, просмотреть конфигурацию php.ini и права доступа. Но для критичных проектов (платежи, персональные данные) лучше привлечь внешнего специалиста: у команды, которая писала код, обычно замылен взгляд.
Закажите аудит PHP-кода и узнайте, где проект уязвим
Получите отчёт с приоритетами исправлений и понятным планом работ на ближайшие спринты
Спасибо за заявку!
Мы свяжемся с вами в ближайшее время.
Проверяем проекты на PHP 7.4–8.x



