PHP Antivirus — это консольный middleware/utility-скрипт для базовой проверки файлов и директорий на признаки вредоносного кода с помощью регулярных выражений-сигнатур. Проект ориентирован на DevOps- и backend-сценарии: ручная проверка web-root, интеграция в cron, CI/CD pipeline, pre-deploy проверки и первичный аудит подозрительных файлов.
Текущая версия в исходном коде: 1.0
Лицензия: MIT
Автор: Roman Tarasenko
- Рекурсивное сканирование директорий.
- Сканирование отдельного файла.
- Проверка только заданного набора расширений.
- Встроенный набор сигнатур для поиска типичных вредоносных конструкций.
- Поддержка внешнего файла сигнатур.
- Проверка валидности regex-сигнатур перед использованием.
- Обнаружение подозрительных PHP/JS/web-shell паттернов:
eval,assert,base64_decode,shell_exec,system,passthru,proc_open,pcntl_exec;create_function,call_user_func,curl_exec,fsockopen,gzuncompress,str_rot13;- подозрительные
<script>,<iframe>,<object>,<embed>; - формы, похожие на phishing/login/banking/paypal/wallet страницы;
- запись входящего потока
php://input; - устаревший и опасный
preg_replace(... /e ...); - загрузка файлов через
move_uploaded_file/copyиз$_FILES.
- Пропуск известных бинарных форматов по magic bytes.
- Обработка больших файлов чанками.
- Краткий и подробный режим логирования.
- Запись логов в файл.
- JSON-отчёт для автоматизированной обработки.
- Перемещение найденных угроз в карантин.
- Генерация JSON metadata-файла для каждого объекта в карантине.
- Корректные exit codes для использования в shell/CI/CD.
- PHP 7.4+ или PHP 8.x.
- CLI-доступ к PHP.
- Права на чтение сканируемых файлов.
- Права на запись, если используется лог-файл или карантин.
Проверить версию PHP:
php -vСклонируйте репозиторий или скачайте файл antivirus.php:
git clone https://github.com/Roman2004de/php-antivirus.git
cd php-antivirusСкрипт не требует Composer-зависимостей и запускается напрямую через PHP CLI.
Сканирование директории:
php antivirus.php --path=/var/www/htmlСканирование одного файла:
php antivirus.php --path=/var/www/html/index.phpПодробный вывод:
php antivirus.php --path=/var/www/html --log-mode=verboseJSON-отчёт:
php antivirus.php --path=/var/www/html --json-reportСохранение логов:
php antivirus.php --path=/var/www/html --log-file=/var/log/php-antivirus.logПеремещение найденных угроз в карантин:
php antivirus.php --path=/var/www/html --quarantine=/var/quarantine/php-antivirusИспользование внешнего файла сигнатур:
php antivirus.php \
--path=/var/www/html \
--signatures-file=/opt/php-antivirus/signatures.txt| Параметр | Обязательный | Значение по умолчанию | Описание |
|---|---|---|---|
--path |
Да | — | Путь к файлу или директории для сканирования. |
--signatures-file |
Нет | встроенные сигнатуры | Путь к внешнему файлу regex-сигнатур. |
--log-mode |
Нет | short |
Режим логирования: short или verbose. |
--log-file |
Нет | не используется | Путь к файлу для записи логов. |
--quarantine |
Нет | не используется | Директория, куда будут перемещены найденные угрозы. |
--json-report |
Нет | false |
Вывод результата в JSON-формате. |
Справка выводится автоматически, если не передан обязательный параметр --path:
php antivirus.phpРежим по умолчанию. Показывает только ошибки, найденные угрозы и финальный результат.
php antivirus.php --path=/var/www/html --log-mode=shortПодробный режим. Показывает процесс обхода директорий и проверки файлов.
php antivirus.php --path=/var/www/html --log-mode=verboseПри использовании --json-report итоговый результат выводится в STDOUT в формате JSON.
Пример:
{
"total_scanned": 128,
"threats_found": 2,
"runtime_errors": 0,
"infected_files": [
"/var/www/html/upload/shell.php",
"/var/www/html/cache/backdoor.phtml"
]
}Логи и ошибки при включённом JSON-режиме пишутся в STDERR, чтобы не ломать JSON-вывод и позволить безопасно парсить результат в CI/CD или shell-скриптах.
Файл сигнатур должен содержать по одной regex-сигнатуре на строку.
Пример signatures.txt:
/\beval\s*\(/i
/\bbase64_decode\s*\(/i
/file_put_contents\s*\(\s*["']php:\/\/input["']\s*,/i
/<\s*iframe\b/iЗапуск с внешними сигнатурами:
php antivirus.php \
--path=/var/www/html \
--signatures-file=./signatures.txtЕсли внешний файл сигнатур не передан или не найден, скрипт использует встроенный набор сигнатур.
Важно: каждая сигнатура должна быть валидным PHP PCRE-выражением, включая разделители, например
/pattern/i.
Скрипт сканирует только файлы с расширениями из внутреннего allowlist:
php, js, phtml, phtm, cgi, pl, o, so, py, sh,
php3, php4, php5, php6, php7, pht, shtml,
susp, suspected, infected, vir, html, htm, tpl,
inc, css, txt, sql, svg, htaccessФайлы с другими расширениями при рекурсивном сканировании директорий пропускаются.
Перед чтением содержимого скрипт проверяет сигнатуру начала файла и пропускает известные бинарные форматы:
exepngjpgzippdfrargifelfmp3mp4
Это снижает количество ложных срабатываний и уменьшает нагрузку при сканировании web-директорий.
Файлы размером больше 100 MB не читаются целиком в память. Вместо этого используется блочная обработка:
- размер блока: 32 KB;
- между блоками сохраняется хвост буфера в 512 байт, чтобы не пропустить сигнатуру на границе чанков.
Если передан параметр --quarantine, каждый найденный подозрительный файл перемещается в указанную директорию.
Пример:
php antivirus.php \
--path=/var/www/html \
--quarantine=/var/quarantine/php-antivirusДля каждого файла формируется безопасное уникальное имя:
YYYYMMDD_HHMMSS_<sha256-prefix>_<original-filename>Рядом создаётся metadata-файл:
YYYYMMDD_HHMMSS_<sha256-prefix>_<original-filename>.jsonПример metadata:
{
"original_path": "/var/www/html/upload/shell.php",
"quarantined_path": "/var/quarantine/php-antivirus/20250201_120000_abcd1234ef567890_shell.php",
"sha256": "abcd1234...",
"quarantined_at": "2025-02-01T12:00:00+00:00",
"original_name": "shell.php"
}Скрипт использует exit codes, чтобы его можно было безопасно применять в автоматизации.
| Код | Константа | Значение |
|---|---|---|
0 |
EXIT_CLEAN |
Угрозы не найдены, ошибок выполнения нет. |
1 |
EXIT_THREATS_FOUND |
Найдены подозрительные или заражённые файлы. |
2 |
EXIT_CLI_ERROR |
Ошибка CLI-вызова, например не передан --path. |
3 |
EXIT_RUNTIME_ERROR |
Критическая runtime-ошибка, например путь не существует. |
4 |
EXIT_PARTIAL_ERROR |
Сканирование завершено, но были runtime-ошибки чтения/обхода. |
Пример использования в bash:
php antivirus.php --path=/var/www/html --json-report > report.json
status=$?
case "$status" in
0)
echo "Clean"
;;
1)
echo "Threats found"
;;
2)
echo "CLI usage error"
;;
3)
echo "Runtime error"
;;
4)
echo "Partial scan error"
;;
esacЕжедневное сканирование web-root с логированием:
0 3 * * * /usr/bin/php /opt/php-antivirus/antivirus.php --path=/var/www/html --log-file=/var/log/php-antivirus.log --quarantine=/var/quarantine/php-antivirusПример для shell-шага:
php antivirus.php --path="$CI_PROJECT_DIR" --json-report > antivirus-report.json
status=$?
if [ "$status" -eq 1 ]; then
echo "Malware signatures detected. Check antivirus-report.json"
exit 1
fi
if [ "$status" -ge 2 ]; then
echo "Antivirus scan failed with status: $status"
exit "$status"
fiphp antivirus.php --path=./public --log-mode=verbose- Запускайте сканирование от пользователя с минимально необходимыми правами.
- Для production-серверов используйте
--log-file, чтобы сохранять историю проверок. - Для автоматизации используйте
--json-reportи exit codes. - Перед включением
--quarantineубедитесь, что директория карантина находится вне web-root. - Не удаляйте подозрительные файлы автоматически без ручной проверки.
- Регулярно обновляйте внешний файл сигнатур.
- После обнаружения угроз проверяйте логи веб-сервера, access logs, upload-директории и историю деплоя.
Этот скрипт является сигнатурным сканером и не заменяет полноценные EDR/AV/WAF-решения.
Текущие ограничения:
- Нет поведенческого анализа.
- Нет sandbox-исполнения подозрительного кода.
- Нет AST-парсинга PHP/JS.
- Нет декодирования вложенной обфускации перед проверкой.
- Нет автоматического восстановления файлов из карантина.
- Возможны ложные срабатывания на легитимный код, использующий опасные функции.
- Возможны пропуски новых или сильно обфусцированных угроз.
- При сканировании директории учитываются только расширения из allowlist.
Найденное совпадение означает, что файл содержит подозрительный паттерн, а не обязательно является вредоносным. Всегда выполняйте ручную проверку перед удалением или окончательной блокировкой файла.
Особое внимание стоит уделять файлам, содержащим:
- динамическое выполнение кода;
- вызовы shell-команд;
- сетевые функции;
- загрузку и перемещение пользовательских файлов;
- запись в
php://input; - обфускацию через base64/gzip/rot13;
- HTML/JS-вставки в неожиданных местах.
Минимальная структура:
php-antivirus/
├── antivirus.php
├── signatures.txt
└── README.mdГде:
antivirus.php— основной CLI-скрипт сканера;signatures.txt— опциональный внешний файл сигнатур;README.md— документация проекта.
Потенциальные направления развития:
- Добавить режим
--deleteдля удаления после подтверждения. - Добавить restore-команду для восстановления из карантина.
- Добавить конфигурационный файл
config.jsonилиconfig.yaml. - Добавить исключения директорий и файлов.
- Добавить настройку списка расширений через CLI.
- Добавить severity-level для сигнатур.
- Добавить structured JSONL logs.
- Добавить unit-тесты для regex-сигнатур и quarantine logic.
- Добавить GitHub Actions workflow для проверки pull requests.
- Добавить поддержку Composer-пакета.
Проект распространяется под лицензией MIT.
Инструмент предназначен для первичного анализа и автоматизированной проверки файлов на известные подозрительные паттерны. Используйте его как дополнительный слой защиты, а не как единственный механизм безопасности.