Назад к обновлениям
New releaseSep 3, 2026

laravel-threat-detection v1.7.2

Пассивное middleware для Laravel, которое обнаруживает и логирует SQL-инъекции, XSS, RCE, бот-сканеры и более 175 паттернов атак. Включает встроенную панель управления, уведомления в Slack, REST API и геообогащение. IDS, а не WAF.

Поделиться

Latest Version Tests PHPStan Level 5 Code Style Pint Total Downloads PHP Version License

Laravel Threat Detection

Мониторинг безопасности и журналирование атак для Laravel. Обнаруживайте и регистрируйте SQL-инъекции, XSS, RCE, обход каталогов, бот-сканеры и разведывательные запросы в стиле /wp-admin — каждый враждебный запрос записывается в вашу базу данных с полным контекстом приложения. Это IDS, а не WAF: он никогда не блокирует, не фильтрует и не изменяет запрос.

Установите пакет, отправьте три атаки — SQL-инъекцию, обход каталогов, XSS — каждая возвращает HTTP 200, потому что ничего не блокируется, и все три уже учтены в threat-detection:stats

Вы здесь, потому что видели что-то подобное?```

GET /wp-admin/setup-config.php 404 — on a site that isn't WordPress GET /.env 404 — someone wants your database password GET /?id=1' UNION SELECT password FROM 200 — SQL injection against a real route GET /phpmyadmin/index.php 404 — scanning for an admin panel

Эти запросы уже достигают вашего Laravel-приложения. Ваш журнал доступа показывает URL
и код статуса — и ничего больше: ни декодированной полезной нагрузки, ни того, какой из ваших
маршрутов был атакован, ни того, пытался ли тот же IP-адрес сделать сорок других вещей за этот час.

Этот пакет отвечает на эти вопросы. Установите его в любое приложение Laravel 10–13, и он начнёт
сканировать каждый HTTP-запрос по 150+ шаблонам атак, оценивая каждое совпадение по
степени уверенности и записывая его в вашу базу данных — со встроенной панелью мониторинга, Slack-оповещениями,
гео-обогащением и экспортом для fail2ban/блок-списков. Ни один запрос никогда не блокируется. Думайте об этом
как о камере видеонаблюдения, а не как о замке: он показывает вам, кто именно прощупывает ваши маршруты, как
часто и с помощью каких техник.

> Извлечён из продакшн-приложения и проверен на реальном трафике. 335 тестов, никаких зависимостей
> времени выполнения, кроме самого Laravel, и для обнаружения не требуется подключение к интернету.
>
> Обновляетесь? См. [UPGRADING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/UPGRADING.md). Хотите внести вклад? См. [CONTRIBUTING.md](https://github.com/jay123anta/laravel-threat-detection/blob/main/CONTRIBUTING.md).

## Начало работы менее чем за минуту```bash
composer require jayanta/laravel-threat-detection
php artisan vendor:publish --tag=threat-detection-migrations
php artisan migrate

Затем добавьте middleware в вашу группу web (одна строка в bootstrap/app.php на Laravel 11+, или в app/Http/Kernel.php на Laravel 10) — полный фрагмент приведён в разделе Quick Start ниже. Всё, обнаружение активно.```bash php artisan threat-detection:doctor # confirms it is actually recording

---

## Где он вписывается: IDS против WAF против edge

Этот пакет — **пассивная IDS уровня приложения** — он наблюдает и записывает, но не
блокирует. Он предназначен для работы *вместе* с WAF или edge-сервисом, а не вместо них. Каждый уровень видит
то, чего не видят другие:

| | **Этот пакет** (IDS приложения) | **WAF** (mod_security, Cloudflare WAF) | **Edge / CDN** (Cloudflare) |
|---|:---:|:---:|:---:|
| Блокирует вредоносные запросы | ❌ только логирует | ✅ | ✅ |
| Полный контекст приложения (точный маршрут, декодированный payload, аутентифицированный пользователь) | ✅ | ⚠️ частично | ❌ |
| Встроенная панель управления + журнал угроз в вашей БД | ✅ | ⚠️ зависит | ⚠️ только edge |
| Специфичные для приложения детекции (например, Aadhaar / PAN / IFSC PII) | ✅ пользовательские паттерны | ❌ | ❌ |
| Работает офлайн / без внешнего сервиса | ✅ | ⚠️ зависит | ❌ |
| Останавливает трафик до того, как он достигнет вашего приложения | ❌ | ✅ edge | ✅ |
| Установка | один `composer require` | средняя–высокая | низкая–средняя |
| Стоимость | бесплатно, MIT | зависит | бесплатный тариф + платный |

**Коротко:** edge/WAF — это ваш замок на двери; этот пакет — камера видеонаблюдения
*внутри*, с контекстом приложения, чтобы точно сказать, что пытаются сделать на каком маршруте, кем
и как часто. Используйте его для принятия реальных решений — банов fail2ban, ограничений скорости,
гео-блокировок — на основе данных, которые ваш edge-уровень никогда не видит.

### Чем он намеренно НЕ является

- **Не WAF.** Он никогда не блокирует, не фильтрует и не изменяет запрос. Используйте Cloudflare,
  mod_security или настоящий WAF для принудительного применения. (Нет edge-уровня для передачи? 
  [Вспомогательные функции на стороне оператора](#acting-on-the-data-operator-side-blocking) раскрывают
  решения пакета, чтобы вы могли написать собственное пятистрочное блокирующее middleware —
  код принудительного применения остаётся вашим, а не пакета.)
- **Не замена безопасному кодированию.** Параметризованные запросы, валидация ввода и
  экранирование вывода — ваша настоящая защита. Этот пакет предполагает, что ваш код уже
  безопасен, и даёт вам *видимость*, а не защиту.
- **Не edge-сервис.** Если вы можете поставить Cloudflare впереди — сделайте это — затем добавьте этот пакет для
  деталей уровня приложения, которые edge-сервисы не видят.

### Так что же с ним на самом деле делать?

Самый частый вопрос о детекторе, который никогда не блокирует. Четыре ответа, в
порядке возрастания усилий:

| Вы хотите | Используйте | Усилия |
|---|---|---|
| Видеть, что на вас направлено | [Панель управления](#dashboard) или `threat-detection:stats` | нет, уже работает |
| Забанить повторных нарушителей на файрволе | [`threat-detection:export-fail2ban`](#artisan-commands) — передать в cron | одна строка |
| Отклонить на веб-сервере | [`threat-detection:export-blocklist`](#artisan-commands) → директивы nginx/apache | одна строка |
| Отказать в запросах внутри приложения | [Вспомогательные функции на стороне оператора](#acting-on-the-data-operator-side-blocking) — `isBlocklisted()`, `isDdosThresholdExceeded()` | ~10 строк вашего собственного middleware |
| Реагировать в реальном времени | [Событие `ThreatDetected`](#threatdetected-event) — Telegram, SIEM, PagerDuty | слушатель |

Пакет предоставляет интеллект; вы предоставляете отказ. Такое разделение
намеренно — код принудительного применения, живущий в вашем приложении, — это код, который вы можете читать,
тестировать и отключать, а значит, ошибка детекции никогда не сможет положить ваш сайт.

### Как он сравнивается с другими пакетами безопасности Laravel

Они решают разные задачи и хорошо сочетаются — таблица о выборе
правильного инструмента, а не о победе.

| Пакет | Что делает | Блокирует? | Используйте, когда |
|---|---|:---:|---|
| **этот пакет** | Сканирует каждый запрос по 150+ паттернам, логирует с полным контекстом приложения | ❌ | Вы хотите *видеть*, что пытаются сделать с вашим приложением |
| `spatie/laravel-honeypot` | Скрытое поле формы, которое ловит спам-ботов | ✅ только форма | У вас публичные формы, заваленные спамом |
| `graham-campbell/security` | Удаляет XSS-подобную разметку из ввода | ✅ изменяет | Вы хотите наивную санитизацию ввода |
| `spatie/laravel-csp` | Отправляет заголовки Content-Security-Policy | ✅ браузер | Вы хотите ограничить, что загружает браузер |
| `laravel/fortify` + ограничения скорости | Троттлинг и блокировка аутентификации | ✅ | Вам нужна защита от brute-force на входе |
| Cloudflare / mod_security | Edge WAF, блокирует до вашего приложения | ✅ | Вы хотите останавливать трафик до его прибытия |

Честное резюме: honeypot ловит спам в формах, WAF блокирует известный вредоносный трафик
на edge, а CSP ограничивает браузер. **Ни один из них не сообщает вам, что
злоумышленник пытался сделать с вашими конкретными маршрутами, с декодированным payload и
прикреплённым аутентифицированным пользователем.** Именно этот пробел заполняет пакет — и именно поэтому он
намеренно не блокирует: вы можете запускать его вместе со всеми вышеперечисленными
без конфликтов между ними.

---

## Требования

- PHP 8.2+ (Laravel 13 требует PHP 8.3+)
- Laravel 10.x, 11.x, 12.x или 13.x
- Любая база данных, поддерживаемая Laravel (MySQL, PostgreSQL, SQLite, SQL Server)
- Любой драйвер кэша — **Redis или очередь worker не требуются**. Redis/Memcached
  только *рекомендуется* для включения опциональной проверки DDoS (которая автоматически отключается на
  неатомарных драйверах). Запись в очередь — опциональна и по умолчанию выключена.

---

## Как это работает

1. Middleware сканирует каждый входящий HTTP-запрос
2. Запрос проверяется по 158 regex-паттернам, покрывающим SQL-инъекции, XSS, RCE, обход файлов, SSRF, LDAP, XPath, SSTI и другое
3. Если паттерн угрозы совпадает, в вашу таблицу базы данных `threat_logs` записывается запись с IP, URL, типом угрозы, уровнем серьёзности и оценкой уверенности
4. Опционально отправляется Slack-оповещение для угроз высокой серьёзности
5. Запрос продолжается нормально — **ничего не блокируется**

Для детекции не требуется подключение к интернету.

---

## Быстрый старт

### 1. Установите пакет```bash
composer require jayanta/laravel-threat-detection

2. Опубликуйте миграции и выполните их

Этот шаг обязателен. Без него пакет будет обнаруживать угрозы, но не сможет сохранять их в базе данных. Если вы пропустите этот шаг, ваша таблица threat_logs не будет создана, и все обнаружения будут молча теряться (вы увидите только ошибки в storage/logs/laravel.log).```bash php artisan vendor:publish --tag=threat-detection-migrations php artisan migrate

Это создаёт две таблицы: `threat_logs` (хранит обнаруженные угрозы) и `threat_exclusion_rules` (хранит правила ложных срабатываний).

**Проверьте, что таблицы были созданы:**```bash
php artisan migrate:status

Look for create_threat_logs_table, add_confidence_to_threat_logs_table, and create_threat_exclusion_rules_table — все должны показывать Ran.

3. Регистрация middleware

Middleware — это то, что сканирует запросы. Вам нужно добавить его в вашу группу middleware web.

Если вы используете Laravel 11 или 12 — откройте bootstrap/app.php:```php ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: [ \JayAnta\ThreatDetection\Http\Middleware\ThreatDetectionMiddleware::class, ]); })

> **Как проверить версию Laravel:** Выполните `php artisan --version` в терминале.

**Если вы используете Laravel 10** — откройте `app/Http/Kernel.php`:```php
protected $middlewareGroups = [
    'web' => [
        // ... existing middleware
        \JayAnta\ThreatDetection\Http\Middleware\ThreatDetectionMiddleware::class,
    ],
];

4. (Необязательно) Опубликуйте файл конфигурации```bash

php artisan vendor:publish --tag=threat-detection-config

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

**Вот и всё.** Ваше приложение теперь обнаруживает угрозы.

---

## Проверьте, что это работает

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

### Шаг 1: Запустите ваше приложение```bash
php artisan serve

Шаг 2: Откройте тестовый URL в вашем браузере

Добавьте вредоносный параметр запроса к любому существующему маршруту в вашем приложении (главная страница, страница товара и т. д.). Например:

SQL-инъекция:``` http://localhost:8000/?q=' UNION SELECT * FROM users--

**XSS (межсайтовый скриптинг):**```
http://localhost:8000/?q=<script>alert(1)</script>

Обход каталога:``` http://localhost:8000/?file=../../etc/passwd

**RCE (удалённое выполнение кода):**```
http://localhost:8000/?cmd=system('ls -la')

Shellshock (CVE-2014-6271):``` http://localhost:8000/?cmd=() { :;}; /bin/bash

**Windows-инъекция команд:**```
http://localhost:8000/?cmd=powershell -c whoami

DROP TABLE (SQL DDL):``` http://localhost:8000/?q=DROP TABLE users

> Используйте маршрут, который действительно существует в вашем приложении (например, `/`). Если URL возвращает 404, промежуточное ПО может не выполниться.

### Шаг 3: Проверьте, что угрозы были зарегистрированы

**Вариант A — команда Artisan (самый быстрый):**```bash
php artisan threat-detection:stats

Вариант B — Tinker:```bash php artisan tinker

```php
DB::table('threat_logs')->latest()->take(5)->get(['ip_address', 'type', 'threat_level', 'confidence_score']);

Вариант C — файл журнала Laravel: Каждая обнаруженная угроза записывается как предупреждение в storage/logs/laravel.log:``` [high] Threat Detected: [middleware] SQL Injection UNION from 127.0.0.1 (http://localhost:8000/?q=...) [confidence: 50%]

### Что нужно знать при тестировании

| Поведение | Пояснение |
|----------|-------------|
| Одна и та же угроза логируется только раз в 5 минут | Дедупликация: один и тот же IP + один и тот же тип угрозы кэшируется на 5 минут. Используйте **разные типы атак** для каждого теста или подождите между тестами. |
| Запросы `curl` вызывают дополнительное обнаружение | Использование `curl` также логирует обнаружение user-agent «cURL Command» (низкая степень серьёзности). Это ожидаемо — пакет обнаруживает автоматизированные инструменты. |
| Пакет никогда не блокирует запросы | Ваше приложение продолжает работать в обычном режиме. Обнаружение пассивно. |
| Настройка Slack не требуется | Уведомления по умолчанию отключены. |
| Подключение к интернету не требуется | Базовое обнаружение работает на 100% локально. Только опциональная команда `threat-detection:enrich` обращается к внешнему API для получения гео-данных. |

### Устранение неполадок

**Начните здесь — одна команда отвечает на большинство вопросов:**```bash
php artisan threat-detection:doctor

Проверяет то, из-за чего обнаружение молча выходит из строя — когда панель мониторинга остаётся пустой, что выглядит так же, как «атак нет», — и выводит точное исправление для каждого случая. При реальном сбое завершается с ненулевым кодом, поэтому его безопасно запускать в CI или на этапе развёртывания.``` Threat Detection — health check

PASS Detection is enabled for this environment FAIL 'threat_logs' is missing confidence_label — EVERY threat is being discarded Run: php artisan vendor:publish --tag=threat-detection-migrations && php artisan migrate WARN 1 custom pattern(s) shadow a built-in: Localhost SSRF Your copy runs instead of the maintained one, so later fixes to it never reach you.

Что охватывает: включённое обнаружение для этого окружения; каждая колонка, которая нужна
писателю (отсутствующая отбрасывает **каждую** угрозу); колонки дашборда/API;
таблица правил исключений; подключено ли промежуточное ПО к маршруту или
группе; опубликованная конфигурация, которая предшествует этой версии; пользовательские шаблоны, перекрывающие
встроенные; драйвер кэша, который не может выполнять подсчёт DDoS; и дашборд или
API, оставленные открытыми без аутентификации.

**«Я тестировал, но `threat-detection:stats` показывает ноль угроз» / «Угрозы не сохраняются в базе данных»**

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

| Проверка | Как проверить |
|-------|---------------|
| IP не в белом списке | Если вы добавили `THREAT_DETECTION_WHITELISTED_IPS` в `.env`, удалите его во время тестирования |
| Использован существующий маршрут | Тестовый URL должен соответствовать реальному маршруту (например, `/`). Код 404 означает, что промежуточное ПО никогда не запускалось |
| Кэш дедупликации | Один и тот же IP + один и тот же тип атаки кэшируется на 5 минут — попробуйте другой тип атаки |

> Выполнения `php artisan migrate` в одиночку никогда не достаточно: файлы миграций
> находятся внутри пакета и должны быть опубликованы в `database/migrations/` вашего приложения
> сначала. Проверка выводит точную команду, когда проблема в этом.

**«API возвращает 401 Unauthorized»**

См. [API Authentication](#api-authentication) ниже.

**«Дашборд показывает 404»**

Дашборд отключён по умолчанию. Добавьте `THREAT_DETECTION_DASHBOARD=true` в `.env` и очистите кэш маршрутов:```bash
php artisan route:clear

Возможности

  • 150+ шаблонов обнаружения — SQL-инъекции (UNION, DDL, DML, файловые операции), XSS (script, SVG, CSS-выражения), RCE, обход каталогов, SSRF, XXE, Log4Shell, NoSQL-инъекции, инъекции команд (Linux + Windows), LDAP-инъекции, XPath-инъекции, SSTI, CRLF-инъекции, десериализация Java и многое другое
  • 83 сигнатуры ботов/сканеров — SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker и более 70 других сигнатур сканеров и ботов
  • Обнаружение AI-скраперов — GPTBot, ClaudeBot, ByteSpider, Common Crawl и другие боты для обучения ИИ
  • Обнаружение headless-браузеров — HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright
  • Отслеживание 404-проб — обнаружение разведывательных проб по известным уязвимым путям (/wp-admin, /.env, /phpmyadmin, /actuator и т. д.) с более чем 50 путями проб по умолчанию
  • Мониторинг DDoS — обнаружение на основе пороговых значений частоты запросов с настраиваемыми окнами
  • Оценка уверенности — каждая угроза получает оценку уверенности от 0 до 100 на основе количества шаблонов, контекста и сигналов
  • Устойчивость к обходу — конвейер нормализации нейтрализует вставку SQL-комментариев, двойное URL-кодирование, кодирование HTML-сущностей, Unicode-экранирование и hex-экранирование до сопоставления с шаблонами
  • Обнаружение CVE — Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell
  • Контекстно-зависимое обнаружение — шаблоны, найденные в строках запроса, получают более высокий балл, чем найденные в теле запроса
  • Сканирование тела запроса — проверяются как тела запросов с кодировкой форм, так и JSON (application/json)
  • Безопасные поля — исключение определённых полей форм из сканирования (для редакторов CMS, полей кода, полей поиска)
  • Отчёт о ложных срабатываниях — пометка угроз как ложных срабатываний с панели управления; автоматическое создание правил исключения
  • Три режима обнаруженияstrict, balanced (по умолчанию) и relaxed — настраиваемая чувствительность
  • Подавление по путям контента — белый список путей CMS/блогов для подавления низких/средних предупреждений от насыщенного контента
  • Обнаружение PII — шаблоны раскрытия конфиденциальных данных (настраиваются по регионам)
  • Гео-обогащение — определение страны, города, интернет-провайдера, облачного провайдера через бесплатный API
  • Оповещения Slack — уведомления в реальном времени об угрозах высокой степени серьёзности (работает на Laravel 10 и 11+)
  • Встроенная панель управления — тёмная Blade-панель (Alpine.js + Tailwind CDN, без этапа сборки)
  • Защита панели управления — настраиваемая аутентификация для панели и API (нет, auth, role или на основе IP)
  • 15 API-эндпоинтов — полноценный REST API для создания собственных Vue/React/мобильных панелей
  • Экспорт Fail2ban — экспорт обнаруженных IP-адресов в совместимом с fail2ban формате или в виде простого блок-листа
  • Экспорт блок-листа — экспорт IP-адресов в формате nginx deny, Apache deny, CSV или простом формате
  • Экспорт CSV — экспорт журнала угроз в один клик (до 10 000 строк)
  • Корреляционный анализ — обнаружение скоординированных атак и кампаний атак по IP-адресам
  • Оптимизация производительности — отложенная загрузка шаблонов по категориям (регулярные выражения выполняются только для релевантных категорий атак), ранний выход для чистых запросов, короткое замыкание по UA браузера (пропуск более 70 проверок для обычных браузеров), поиск по хешу путей проб, пакетная вставка в БД, настраиваемый максимум обнаружений на запрос
  • Независимость от БД — MySQL, PostgreSQL, SQLite, SQL Server
  • Нулевая настройка — работает из коробки с разумными значениями по умолчанию
  • Безопасность по дизайну — промежуточное ПО перехватывает собственные ошибки. Если обнаружение не сработало, ваше приложение продолжает работать. Запросы никогда не блокируются.

Конфигурация

Пакет работает без каких-либо изменений в .env. Все значения ниже необязательны — добавляйте их только в том случае, если хотите переопределить значения по умолчанию.```env

Enable/disable detection globally (default: true)

THREAT_DETECTION_ENABLED=true

Detection sensitivity (default: balanced)

Options: strict, balanced, relaxed

THREAT_DETECTION_MODE=balanced

Custom table name (default: threat_logs)

THREAT_DETECTION_TABLE=threat_logs

Your ISO 3166-1 alpha-2 country code (default: IN)

Drives the is_foreign flag on every enriched row — set this or every

non-Indian address is reported as foreign.

THREAT_DETECTION_HOME_COUNTRY=IN

Geo-enrichment provider used by threat-detection:enrich (default shown).

Cleartext HTTP because ip-api.com's free tier rejects HTTPS; point this at

an HTTPS endpoint if you hold a key. Enrichment is opt-in either way.

THREAT_DETECTION_GEO_ENDPOINT=http://ip-api.com/json

Dashboard URL path (default: threat-detection)

THREAT_DETECTION_DASHBOARD_PATH=threat-detection

API route prefix (default: api/threat-detection)

THREAT_DETECTION_API_PREFIX=api/threat-detection

Role required when the API guard is 'role' (default: admin)

THREAT_DETECTION_API_ROLE=admin

Allowed IPs when the API guard is 'ip'. Comma-separated, CIDR supported.

THREAT_DETECTION_API_IPS=127.0.0.1,10.0.0.0/8

Username shown on Slack alerts (default: ThreatBot)

THREAT_DETECTION_SLACK_USERNAME=ThreatBot

Whitelist IPs to skip detection entirely (default: empty)

Supports CIDR notation. Comma-separated.

THREAT_DETECTION_WHITELISTED_IPS=10.0.0.0/8,192.168.1.0/24

Static operator denylist read by ThreatDetection::isBlocklisted() (default: empty)

The package itself never blocks — see "Acting on the Data" for the

enforcement recipe. Supports CIDR. Whitelist wins on overlap.

THREAT_DETECTION_BLOCKLISTED_IPS=203.0.113.0/24,198.51.100.7

DDoS detection thresholds (defaults shown)

THREAT_DETECTION_DDOS_THRESHOLD=300

THREAT_DETECTION_DDOS_WINDOW=60

Minimum confidence score to log a threat (default: 0)

Threats below this score are silently ignored.

THREAT_DETECTION_MIN_CONFIDENCE=0

Slack notifications (disabled by default)

THREAT_DETECTION_NOTIFICATIONS=true

THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL

THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts

Dashboard (disabled by default)

THREAT_DETECTION_DASHBOARD=true

API endpoints (enabled by default)

THREAT_DETECTION_API=true

API rate limiting (default: 60 requests per minute)

THREAT_DETECTION_API_THROTTLE=60,1

Queue support - offload DB writes to a queue (disabled by default).

OPTIONAL: only enable if your app already runs a queue worker. When false

(default), threats are written synchronously with a plain DB insert - no

Redis, no worker, nothing extra to run.

THREAT_DETECTION_QUEUE=false

THREAT_DETECTION_QUEUE_CONNECTION=redis

THREAT_DETECTION_QUEUE_NAME=default

Auto-purge old logs (disabled by default)

Requires Laravel scheduler to be running.

THREAT_DETECTION_RETENTION=false

THREAT_DETECTION_RETENTION_DAYS=90

404 probe tracking (enabled by default)

Detects bots hitting /wp-admin, /.env, /phpmyadmin, etc.

THREAT_DETECTION_PROBE_TRACKING=true

Max detections per request (default: 0 = unlimited)

Stop scanning after N pattern matches per request.

THREAT_DETECTION_MAX_DETECTIONS=0

Dashboard auth guard (default: none)

Options: none, auth, role, ip

THREAT_DETECTION_DASHBOARD_GUARD=none

THREAT_DETECTION_DASHBOARD_ROLE=admin

THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1

API auth guard (default: none - uses existing middleware config)

THREAT_DETECTION_API_GUARD=none

### Режимы обнаружения

| Режим | Порог уверенности | Поведение |
|------|---------------------|----------|
| `strict` | 0 (логирует всё) | Все паттерны активны, минимальные пороги. Ловит всё, но может помечать легитимный трафик. |
| `balanced` | 10 | По умолчанию. Активно скоринг уверенности, стандартные пороги. Подходит для большинства приложений. |
| `relaxed` | 40 | Срабатывают только паттерны высокой степени серьёзности. Лучше всего подходит для сайтов с большим объёмом контента и частыми ложными срабатываниями. |

### Включённые окружения

По умолчанию обнаружение выполняется в `production`, `staging` и `local`. Чтобы изменить это, опубликуйте конфигурацию и отредактируйте:```php
'enabled_environments' => ['production', 'staging', 'local'],

Чтобы отключить обнаружение в вашем тестовом наборе, установите APP_ENV=testing (не в списке выше) или добавьте в ваш phpunit.xml:```xml

### Config Reference

Опубликуйте файл конфигурации, чтобы увидеть все доступные параметры:```bash
php artisan vendor:publish --tag=threat-detection-config

Ключевые секции конфигурации: skip_paths (пути для пропуска), only_paths (режим белого списка), auth_paths (умное обнаружение маршрутов входа), content_paths (подавление некритических алертов), safe_fields (исключение определённых полей из сканирования), safe_paths (исключение полей с учётом пути для вложенного JSON), probe_tracking (обнаружение 404-проб), context_weights (множители оценки), threat_levels (сопоставление ключевых слов по критичности), api_route_filtering (подавление низких/средних алертов на API-маршрутах), queue (асинхронная обработка), retention (автоочистка), max_detections_per_request (ограничение производительности), dashboard.guard / api.guard (режим аутентификации).

Белый список маршрутов (only_paths)

Если в вашем приложении много маршрутов, но вас интересуют лишь некоторые, используйте only_paths, чтобы сканировать только эти маршруты. Все остальные маршруты автоматически пропускаются — никаких накладных расходов на middleware.```php // config/threat-detection.php 'only_paths' => [ 'admin/', 'api/', 'login', 'register', ],

Оставьте пустым (по умолчанию) для сканирования всех маршрутов (с учётом `skip_paths`). Когда настроены оба параметра, сначала проверяется `only_paths`, затем `skip_paths` применяется в пределах совпавшего набора.

### Поддержка очередей

По умолчанию запись угроз выполняется синхронно в цикле обработки запроса. Для приложений с высокой нагрузкой вы можете выгрузить записи в БД и уведомления Slack в очередь:```env
THREAT_DETECTION_QUEUE=true
THREAT_DETECTION_QUEUE_CONNECTION=redis
THREAT_DETECTION_QUEUE_NAME=threat-logs

Это отправляет задание StoreThreatLog (3 повтора, backoff 10с/30с). Обнаружение по-прежнему происходит в реальном времени — откладывается только запись.

Автоочистка (Политика хранения)

Автоматическое удаление старых журналов угроз по ежедневному расписанию:```env THREAT_DETECTION_RETENTION=true THREAT_DETECTION_RETENTION_DAYS=90

Требует запущенного планировщика Laravel (`php artisan schedule:run`). Выполняется ежедневно в 02:00 через `threat-detection:purge`.

### Событие ThreatDetected

Каждая подтверждённая угроза отправляет событие `ThreatDetected`, на которое вы можете подписаться:```php
// app/Providers/EventServiceProvider.php
use JayAnta\ThreatDetection\Events\ThreatDetected;

protected $listen = [
    ThreatDetected::class => [
        YourCustomListener::class,
    ],
];

The event carries $threatLog (full DB row array), $ipAddress, and $threatLevel. Use it to trigger custom actions - send Telegram alerts, update a blocklist, feed a SIEM, etc.

DdosThresholdExceeded Event

When a client crosses the configured DDoS threshold (ddos.threshold requests within ddos.window seconds), a DdosThresholdExceeded event is dispatched alongside the threat log entry:```php use JayAnta\ThreatDetection\Events\DdosThresholdExceeded;

protected $listen = [ DdosThresholdExceeded::class => [ YourFloodListener::class, ], ];

Событие содержит `$ipAddress`, `$requestCount`, `$threshold` и `$windowSeconds`. Оно
ограничивается одним событием на IP за окно дедупликации (то же ограничение, что и для строки журнала), поэтому поток запросов не может
перегрузить ваши слушатели. Используйте его для оповещений или для передачи во внешнее хранилище банов; чтобы *отказать*
клиентам, превысившим порог, используйте `ThreatDetection::isDdosThresholdExceeded($ip)` из собственного
промежуточного ПО — см. [Действия на основе данных](#acting-on-the-data-operator-side-blocking).

---

## Уведомления Slack

Уведомления Slack отключены по умолчанию. Чтобы включить:```env
THREAT_DETECTION_NOTIFICATIONS=true
THREAT_DETECTION_SLACK_WEBHOOK=https://hooks.slack.com/services/YOUR/WEBHOOK/URL
THREAT_DETECTION_SLACK_CHANNEL=#threat-alerts

Только угрозы высокой степени серьёзности запускают уведомления по умолчанию (настраивается через notify_levels в конфигурации).

Laravel 10: Использует встроенный класс уведомлений SlackMessage. Дополнительный пакет не требуется.

Laravel 11+: Встроенный Slack-канал был удалён. Пакет автоматически определяет это и отправляет сырые HTTP POST вебхуки на ваш Slack URL. Дополнительный пакет не требуется. Если вы предпочитаете полноценный канал уведомлений, установите:```bash composer require laravel/slack-notification-channel

---

## Панель управления

<p align="center">
  <img src="https://assets.kitploit.com/production/public/readmes/12500/fc7950bd0cc6323bcc2d62b03e31c99edc7450b0ef76f9cbfa5133b527b25269.png" alt="Панель обнаружения угроз — статистика, временная шкала за 7 дней, журнал угроз в реальном времени, основные IP-адреса нарушителей и угрозы по странам" width="100%">
</p>

Пакет поставляется со встроенной панелью управления в тёмном режиме (Alpine.js + Tailwind CDN — этап сборки не требуется).```
+-------------------------------------------------------------------------+
|  Threat Detection Dashboard                                              |
+-------------------------------------------------------------------------+
|  Total: 847  |  High: 23  |  Med: 156  |  Low: 668  |  IPs: 94         |
+-------------------------------------------------------------------------+
|  [Timeline Chart - 7 Day Stacked Bar]                                   |
+-------------------------------------------------------------------------+
|  Search: [___________]  Level: [All]                                    |
|  Time         IP             Type            Level  Confidence  Actions  |
|  Mar 2 14:02  185.220.101.4  SQL Injection   HIGH   80%         [FP]    |
|  Mar 2 13:58  45.33.32.156   XSS Script Tag  HIGH   65%         [FP]    |
|  Mar 2 13:45  192.168.1.10   Scanner: Nikto  MED    35%         [FP]    |
+-------------------------------------------------------------------------+
|  Top IPs              |  Threats by Country                              |
|  185.220.101.4  [23]  |  US  234                                        |
|  45.33.32.156   [18]  |  CN  156                                        |
|  103.152.220.1  [12]  |  RU  98                                         |
+-------------------------------------------------------------------------+

Включите панель управления

Добавьте в .env:```env THREAT_DETECTION_DASHBOARD=true

Посетите: `http://your-app.test/threat-detection`

### Доступ во время локальной разработки

Панель управления по умолчанию использует middleware `['web', 'auth']`, поэтому пользователи должны быть авторизованы. Если в вашем приложении ещё нет аутентификации, ограничьте доступ только вашей машиной:```env
THREAT_DETECTION_DASHBOARD_GUARD=ip
THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1

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

Если панель управления показывает пустые данные, страница загрузилась, но её API-вызовы не выполнились. См. Аутентификация API.


Конечные точки API

Пакет предоставляет 15 REST-конечных точек для создания пользовательских панелей управления или интеграций.

Аутентификация API

Маршруты API по умолчанию используют промежуточное ПО auth:sanctum. Пакет обрабатывает это корректно:

  • Sanctum установлен: API требует аутентификации через токены Sanctum или аутентификацию по SPA-сессии.
  • Sanctum НЕ установлен: Пакет автоматически определяет, что Sanctum отсутствует, и переключается только на ['api']. API работает без аутентификации.

Если вы не используете Sanctum, но хотите защитить свой API, у вас есть два варианта:

Вариант 1 — Использовать встроенную защиту аутентификации:```env THREAT_DETECTION_API_GUARD=auth

**Вариант 2 — Изменить middleware напрямую:**```php
// config/threat-detection.php
'api' => [
    'enabled' => true,
    'prefix' => 'api/threat-detection',
    'middleware' => ['api', 'auth'],  // or 'auth:your-guard'
],

Для локального тестирования (если Sanctum блокирует доступ), временно измените:```php 'middleware' => ['api'], // remove 'auth:sanctum'

> Восстановите аутентификацию перед развёртыванием в производственной среде.

### Справочник по конечным точкам

| Метод | Конечная точка | Описание |
|--------|----------|-------------|
| GET | `/api/threat-detection/threats` | Список угроз (с пагинацией и фильтрацией) |
| GET | `/api/threat-detection/threats/{id}` | Детали отдельной угрозы |
| POST | `/api/threat-detection/threats/{id}/false-positive` | Пометить угрозу как ложное срабатывание |
| GET | `/api/threat-detection/stats` | Общая статистика |
| GET | `/api/threat-detection/summary` | Детальная разбивка по типу, уровню, IP |
| GET | `/api/threat-detection/live-count` | Угрозы за последний час |
| GET | `/api/threat-detection/by-country` | Сгруппировано по странам |
| GET | `/api/threat-detection/by-cloud-provider` | Сгруппировано по облачному провайдеру |
| GET | `/api/threat-detection/top-ips` | Наиболее активные IP-адреса нарушителей |
| GET | `/api/threat-detection/timeline` | Временная шкала угроз (для графиков) |
| GET | `/api/threat-detection/ip-stats?ip=x.x.x.x` | Статистика для конкретного IP |
| GET | `/api/threat-detection/correlation` | Корреляционный анализ |
| GET | `/api/threat-detection/export` | Экспорт в CSV |
| GET | `/api/threat-detection/exclusion-rules` | Список правил исключения |
| DELETE | `/api/threat-detection/exclusion-rules/{id}` | Удалить правило исключения |

### Параметры запроса для `/threats`

| Параметр | Описание |
|-----------|-------------|
| `keyword` | Поиск по IP, URL, типу |
| `ip` | Фильтр по IP-адресу |
| `level` | Фильтр по уровню угрозы (`high`, `medium`, `low`) |
| `type` | Фильтр по типу угрозы |
| `country` | Фильтр по коду страны |
| `is_foreign` | Фильтр внешних IP (`true`/`false`) |
| `cloud_provider` | Фильтр по облачному провайдеру |
| `is_false_positive` | Фильтр по статусу ложного срабатывания (`true`/`false`) |
| `date_from` / `date_to` | Фильтр по диапазону дат |
| `per_page` | Элементов на странице (по умолчанию: 20, максимум: 100) |

### Пример ответа API

**GET `/api/threat-detection/stats`:**```json
{
  "success": true,
  "data": {
    "total_threats": 847,
    "high_severity": 23,
    "medium_severity": 156,
    "low_severity": 668,
    "unique_ips": 94,
    "foreign_ips": 67,
    "cloud_attacks": 12,
    "today": 34,
    "last_hour": 5
  }
}

Создание пользовательских интерфейсов

Vue.js:```javascript async mounted() { const response = await fetch('/api/threat-detection/stats'); this.stats = await response.json();

const threats = await fetch('/api/threat-detection/threats?per_page=20');
this.threats = await threats.json();

}

**React:**```jsx
useEffect(() => {
    fetch('/api/threat-detection/stats')
        .then(res => res.json())
        .then(data => setStats(data));
}, []);

Если ваш API использует auth:sanctum, включите заголовки аутентификации или настройте SPA-аутентификацию Sanctum для запросов на основе cookie.


Команды Artisan```bash

Check that detection is installed, wired up and actually recording.

Exits non-zero on a real failure, so it works in CI or a deploy step.

php artisan threat-detection:doctor

View threat stats summary in the terminal

php artisan threat-detection:stats

Enrich existing logs with geo-data (country, city, ISP, cloud provider)

Uses the free ip-api.com service (rate-limited to 45 req/min, auto-throttled)

php artisan threat-detection:enrich --days=7

Purge old logs to keep the database clean

php artisan threat-detection:purge --days=30

Export threat IPs for fail2ban (pipe to file or run directly)

php artisan threat-detection:export-fail2ban --level=high --since=24h --min-hits=5 php artisan threat-detection:export-fail2ban --format=plain > /tmp/banlist.txt

Export blocklist in various formats

php artisan threat-detection:export-blocklist --format=nginx > /etc/nginx/blocklist.conf php artisan threat-detection:export-blocklist --format=apache > .htaccess-deny php artisan threat-detection:export-blocklist --format=csv --since=7d

---

## Принятие мер на основе данных (блокировка на стороне оператора)

Пакет никогда не блокирует запрос — это его суть, а не значение по умолчанию. Указанные выше экспорты
питают уровни принуждения, которые вы уже запускаете (fail2ban, nginx, периферийный WAF). Но в некоторых развертываниях
такого уровня нет — общий хостинг, PaaS, контейнеры за балансировщиком нагрузки, которым вы
не управляете. Для таких случаев пакет предоставляет свои *решения* в виде помощников, а вы сами пишете
промежуточное ПО для принуждения. Та же архитектура, что и у экспортов: **мы предоставляем
интеллект, вы обеспечиваете отказ.**```php
// app/Http/Middleware/EnforceThreatDecisions.php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use JayAnta\ThreatDetection\Facades\ThreatDetection;

class EnforceThreatDecisions
{
    public function handle(Request $request, Closure $next)
    {
        $ip = (string) $request->ip();

        // Static operator denylist (config: blocklisted_ips).
        // CIDR supported; whitelisted_ips wins on overlap.
        if (ThreatDetection::isBlocklisted($ip)) {
            abort(403);
        }

        // Volumetric flood: refuse over-threshold clients until the window resets.
        if (ThreatDetection::isDdosThresholdExceeded($ip)) {
            return response('Too Many Requests', 429, [
                'Retry-After' => (string) config('threat-detection.ddos.window', 60),
            ]);
        }

        return $next($request);
    }
}

Прежде чем применять ограничения по IP, настройте TrustProxies.

Всё вышеперечисленное завязано на $request->ip(). За балансировщиком нагрузки, CDN или обратным прокси этот метод возвращает IP клиента только тогда, когда Laravel знает, каким прокси доверять. Если этого не сделать, ломаются сразу две вещи: каждый запрос выглядит так, будто приходит от прокси, поэтому запись в денай-листе блокирует либо весь ваш трафик, либо ничего — и хуже того, если приложение доверяет пересылаемому заголовку, которому доверять не следует, злоумышленник задаёт X-Forwarded-For и проходит сквозь блок-лист напрямую.

Это важнее здесь, чем для whitelisted_ips. Ошибочное совпадение в вайт-листе означает лишь, что пакет просканирует запрос, который мог бы пропустить: это безопасный отказ. Денай-лист, используемый для отказа в трафике, даёт сбой открыто — вы считаете, что адрес заблокирован, когда это не так. Проверьте app/Http/Middleware/TrustProxies.php (или вызов trustProxies в bootstrap/app.php на Laravel 11+) перед тем, как полагаться на любой из этих помощников для применения ограничений.

Зарегистрируйте его глобально (до middleware обнаружения — это нормально: помощники читают конфигурацию и кэш, они не зависят от порядка middleware):```php // bootstrap/app.php (Laravel 11+) ->withMiddleware(function ($middleware) { $middleware->prepend(\App\Http\Middleware\EnforceThreatDecisions::class); })

Вспомогательные методы:

| Метод | Возвращает | Основан на |
|---|---|---|
| `ThreatDetection::isBlocklisted($ip)` | `bool` | конфиг `blocklisted_ips` (CIDR через `IpUtils`; белый список имеет приоритет) |
| `ThreatDetection::isWhitelisted($ip)` | `bool` | конфиг `whitelisted_ips` |
| `ThreatDetection::ddosRequestCount($ip)` | `int` | счётчик флуда, который ведёт промежуточное ПО обнаружения |
| `ThreatDetection::isDdosThresholdExceeded($ip)` | `bool` | этот счётчик по сравнению с `ddos.threshold` |

Примечания:

- **Чёрный список статичен и поддерживается оператором.** Ничто в пакете никогда не добавляет в него записи —
  он выполняет то же решение, которое приняла бы тюрьма fail2ban («я прочитал панель управления; эта /24
  враждебна»), просто внутри приложения.
- Счётчик DDoS учитывает только запросы, которые достигли этапа обнаружения (`skip_paths`, IP из белого
  списка и отключённые окружения никогда не учитываются) и остаётся на 0 в драйверах кэша, где
  обнаружение DDoS отключено (`file`, `database`, `null`).
- Когда клиент превышает порог, также отправляется событие [`DdosThresholdExceeded`](#ddosthresholdexceeded-event)
  — полезно для оповещения или передачи во внешний список блокировок. Однако не вызывайте `abort()`
  из слушателя: слушатели выполняются внутри `try/catch` промежуточного ПО обнаружения с отказоустойчивым
  поведением, поэтому отказ должен обрабатываться в вашем собственном промежуточном ПО, как описано выше.

---

## Отслеживание 404-зондирования

Пакет обнаруживает разведывательные зонды — ботов, которые обращаются к известным уязвимым путям, таким как `/wp-admin`, `/.env` или `/phpmyadmin`, на вашем сайте, не являющемся WordPress или phpMyAdmin. В таких запросах нет вредоносной полезной нагрузки; сам путь и есть сигнал.

Записывается с тегом типа `[probe]`, отдельно от обнаружения на основе полезной нагрузки. Если запрос-зонд также содержит вредоносную полезную нагрузку, оба события регистрируются независимо.

Включено по умолчанию с более чем 50 путями зондирования. Настройка в `config/threat-detection.php`:```php
'probe_tracking' => [
    'enabled' => true,
    'default_level' => 'medium',
    'paths' => [
        '/wp-admin' => 'WordPress Admin',
        '/wp-admin/*' => 'WordPress Admin',
        '/.env' => 'Environment File',
        '/phpmyadmin' => 'phpMyAdmin',
        '/actuator/*' => 'Spring Actuator',
        // Add your own probe paths...
    ],
],

Отключите с помощью THREAT_DETECTION_PROBE_TRACKING=false.


Безопасные поля (снижение ложных срабатываний)

Если определённые поля форм на законных основаниях содержат HTML, SQL-ключевые слова или код (например, редакторы CMS, поля ввода фрагментов кода), вы можете исключить их из сканирования:```php // config/threat-detection.php 'safe_fields' => ['content', 'body', 'html', 'description', 'code'],

Поля, перечисленные здесь, удаляются из параметров запроса и тела запроса — как в форме (`application/x-www-form-urlencoded`), так и в JSON (`application/json`) — до запуска детектирования. Остальные поля того же запроса по-прежнему полностью сканируются.

### Безопасные пути (с учётом пути, для вложенных JSON API)

`safe_fields` сопоставляет имя ключа **где угодно**, где оно встречается. Для вложенных JSON API это часто слишком широко — вам может понадобиться исключить значение одного конкретного поля, не исключая этот ключ повсюду. Используйте `safe_paths`, который сопоставляет по **пути** в точечной нотации и поддерживает подстановочные знаки `fnmatch`:```php
// config/threat-detection.php
'safe_paths' => ['search.query', 'filters.*.value'],

Например, search.query исключает значение {"search": {"query": "..."}} (поле поиска, текст которого легитимно содержит слова вроде SELECT), тогда как поле query в любом другом месте запроса по-прежнему сканируется. Всё, что не перечислено, сканируется точно так же, как и раньше.

Пост-матч валидаторы (снижение ложных срабатываний с учётом контрольной суммы)

Одного регулярного выражения недостаточно, чтобы выразить любое ограничение: любая последовательность из 12 цифр соответствует шаблону Aadhaar, но настоящий номер Aadhaar также проходит контрольную сумму Верхоффа. Сопоставьте метку шаблона (по умолчанию или пользовательскую) с именованным валидатором, и совпадение по регулярному выражению будет считаться обнаружением только тогда, когда хотя бы одно совпавшее значение пройдёт его проверку:```php // config/threat-detection.php 'pattern_validators' => [ 'Aadhaar Number Detected' => 'verhoeff', // shipped default ],

Доступные валидаторы:

| Валидатор  | Контрольная сумма | Типичное использование |
|------------|-------------------|------------------------|
| `verhoeff` | Verhoeff          | Номера Aadhaar         |
| `luhn`     | Luhn              | Номера кредитных/дебетовых карт |

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

Скомбинируйте валидатор с собственным шаблоном для обнаружения карт с проверкой контрольной суммы:```php
'custom_patterns'    => ['/\b(?:\d[ -]?){13,19}\b/' => 'Card Number Detected'],
'pattern_validators' => ['Card Number Detected' => 'luhn'],

Неизвестное имя валидатора открывается в режиме fail-open — совпадение засчитывается без проверки, а предупреждение логируется один раз, — поэтому опечатка никогда не сможет незаметно отключить шаблон обнаружения. Конфигурации, опубликованные до появления этой функции, просто не содержат этого ключа и сохраняют своё текущее поведение без изменений.


Редактирование (Обнаружение — это не хранение)

Обнаружение чувствительных данных раньше означало их хранение. Форма профиля с номером мобильного телефона, PAN и банковским счётом вызывала срабатывание трёх PII-шаблонов, и каждая из трёх записанных строк сохраняла всё тело запроса дословно — с удержанием в течение всего срока хранения, доступным для чтения любому, у кого есть доступ к панели управления или базе данных. Значение в строке запроса также попадало в столбец url. Детектор становился второй, концентрированной копией именно того, о чём он вас предупреждает.

Включено по умолчанию с версии v1.7.0. Когда срабатывает шаблон, метка которого указана в списке, совпавшее с ним значение маскируется в сохранённой полезной нагрузке и URL:``` BODY: {"name":"Jane Doe","mobile":"[REDACTED]","pan":"[REDACTED]","bank_account":"[REDACTED]"}

The alert, the endpoint, the field names and the attacking IP all survive -  only the value goes. Redaction runs *after* detection, so nothing is missed.```php
// config/threat-detection.php
'redact' => [
    'enabled' => env('THREAT_DETECTION_REDACT', true),
    'mask'    => '[REDACTED]',
    'labels'  => ['Aadhaar Number Detected', 'PAN Number Detected', /* ... */],
],

Атакующие полезные нагрузки намеренно оставляются нетронутыми — строка инъекции является уликой, а не секретом, и её маскировка уничтожила бы расследование. Изменяются только те метки, которые вы перечислили.

Это не заменяет Безопасные поля. Они предотвращают сканирование поля; редактирование позволяет продолжать сканирование и прекратить хранение. Установите THREAT_DETECTION_REDACT=false, если вам нужны полные полезные нагрузки для криминалистики.


Аутентификация панели управления и API

Панель управления и API поддерживают настраиваемые защитные шлюзы через .env:```env

Options: none (default), auth, role, ip

THREAT_DETECTION_DASHBOARD_GUARD=auth

For role-based guard (Spatie compatible):

THREAT_DETECTION_DASHBOARD_GUARD=role THREAT_DETECTION_DASHBOARD_ROLE=admin

For IP-based guard:

THREAT_DETECTION_DASHBOARD_GUARD=ip THREAT_DETECTION_DASHBOARD_IPS=127.0.0.1,10.0.0.0/8

Те же параметры доступны для маршрутов API с `THREAT_DETECTION_API_GUARD`.

Когда `guard=none` (по умолчанию), пакет один раз в день записывает предупреждение в журнал, напоминая о необходимости настроить аутентификацию.

Защита **отказывает закрыто**: нераспознанное значение guard (например, опечатка) отклоняется с кодом 403 и записью предупреждения в журнал, а не молча предоставляет доступ, а `guard=role` отклоняет запрос (с предупреждением), когда у аутентифицированной модели пользователя нет метода `hasRole()`.

### Отключение обнаружения требует больше, чем доступ на чтение

Пометка угрозы как ложного срабатывания и удаление правила исключения — оба действия отключают тип обнаружения для всех, что является привилегией, отличной от чтения журнала. Эти две конечные точки проверяются отдельной защитой:```env
# Options: none, auth, role, ip. Default: role
THREAT_DETECTION_API_WRITE_GUARD=role

It applies to those routes only, so reading and the dashboard behave exactly as THREAT_DETECTION_API_GUARD says. Without it, any authenticated user of your application could switch a detection off.

If your user model has no hasRole(), use =auth. To restore the pre-1.7.0 behaviour where any authenticated user could disable detections, use =none - threat-detection:doctor will warn while that is set.

Dashboard ↔ API note: the built-in dashboard fetches its data from the API routes using the browser session cookie. If your API routes are protected with auth:sanctum, configure Sanctum stateful/SPA authentication (or point the dashboard at a cookie-authenticated guard) so those AJAX calls are authorised - otherwise the dashboard renders empty.


Custom Patterns

Add your own detection regex patterns in config/threat-detection.php:```php 'custom_patterns' => [ '/your-regex-here/i' => 'Your Threat Label', ],

**Пример — обнаружение проверки пользовательской конечной точки администратора:**```php
'/\/my-admin-panel/i' => 'Custom Admin Panel Probe',

Форма массива (параметры для каждого паттерна)

Наряду с классической строковой формой, значение паттерна может быть массивом для полного контроля:```php 'custom_patterns' => [ '/\b(?:\d[ -]?){13,19}\b/' => [ 'label' => 'Card Number Detected', // required 'level' => 'high', // low|medium|high — overrides keyword derivation 'contexts' => ['query', 'body'], // query|body|headers — default: all segments 'validator' => 'luhn', // post-match checksum, wins over pattern_validators ], ],

- **`level`** задаёт уровень угрозы напрямую, а не выводит его из ключевых слов `threat_levels` в метке.
- **`contexts`** ограничивает сканирование конкретными сегментами запроса — например, шаблон карты, который имеет смысл только в теле, перестаёт совпадать с последовательностями цифр в заголовках.
- **`validator`** указывает встроенную проверку после совпадения (см. [Пост-матчевые валидаторы](#post-match-validators-checksum-aware-false-positive-reduction)); он имеет приоритет над картой меток `pattern_validators`.

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

> **Примечание:** Стандартные пути проверки, такие как `/wp-login.php`, `/.env`, `/phpmyadmin`, теперь обрабатываются автоматически функцией [Отслеживание 404-проб](#404-probe-tracking). Для них не нужны пользовательские шаблоны.

Уровень угрозы для каждого шаблона определяется автоматически путём сопоставления ключевых слов в метке с конфигурацией `threat_levels`:```php
'threat_levels' => [
    'high' => ['XSS', 'SQL Injection', 'SQL DDL', 'SQL DML', 'SQL File', 'SQL Hex', 'RCE', ..., 'Shellshock', 'Spring4Shell', 'PowerShell', 'CRLF', 'Null Byte', 'SSTI', 'Java', 'LDAP', 'XPath', 'PHP assert', ...],
    'medium' => ['Directory Traversal', 'LFI', 'SSRF', 'Sensitive', 'Config', ..., 'Open Redirect', 'LF Injection', 'GraphQL', 'Spring Boot Actuator', ...],
    'low' => ['User-Agent', 'JS Redirect', 'SEO Bot', 'Empty', 'Rate', 'Command-line Downloader', 'DNS Rebinding'],
],

Если метка не соответствует ни одному ключевому слову, угроза по умолчанию получает уровень серьёзности low.

Некорректные regex-шаблоны автоматически пропускаются и логируются как предупреждения — они не приведут к сбою вашего приложения.


Использование фасада

Для программного доступа к данным об угрозах вне middleware:```php use JayAnta\ThreatDetection\Facades\ThreatDetection;

// Get attack statistics for a specific IP $stats = ThreatDetection::getIpStatistics('192.168.1.1');

// Detect coordinated attacks (multiple IPs targeting same URL within 15 minutes) $attacks = ThreatDetection::detectCoordinatedAttacks(15, 3);

// Detect attack campaigns (same threat type from 5+ IPs in last 24 hours) $campaigns = ThreatDetection::detectAttackCampaigns(24);

// Get a summary of all correlation data $summary = ThreatDetection::getCorrelationSummary();

// Operator-side decision helpers (see "Acting on the Data") $blocked = ThreatDetection::isBlocklisted('203.0.113.7'); // static denylist, CIDR, whitelist wins $trusted = ThreatDetection::isWhitelisted('10.0.0.5'); $count = ThreatDetection::ddosRequestCount('203.0.113.7'); // requests in the current DDoS window $flooded = ThreatDetection::isDdosThresholdExceeded('203.0.113.7');

---

## Переход в продакшн

Пакет пассивен по своей конструкции — он никогда не блокирует, не отклоняет и не изменяет запрос, а middleware обнаружения оборачивает всё своё тело в `try/catch`, поэтому сбой обнаружения никогда не сломает ваше приложение. Он поставляется с разумными настройками по умолчанию и не требует внешних сервисов для работы. Перед запуском стоит просмотреть этот краткий чек-лист:

1. **Защитите панель управления и API.** Оба по умолчанию используют `guard = none` для первого запуска без конфигурации и ежедневно записывают предупреждение, пока не защищены. Перед продакшном задайте guard — `THREAT_DETECTION_DASHBOARD_GUARD` и `THREAT_DETECTION_API_GUARD` (`auth`, `role` или `ip`). Неизвестное значение или guard `role` на модели пользователя без `hasRole()` теперь **закрывается с ошибкой** (403), поэтому опечатка не приведёт к тихому раскрытию данных. Отключение обнаружения отдельно ограничивается `THREAT_DETECTION_API_WRITE_GUARD`, который по умолчанию равен `role`. См. [Аутентификация панели управления и API](#dashboard-and-api-authentication).
2. **Запустите миграции** (`vendor:publish --tag=threat-detection-migrations && migrate`). Повторная публикация безопасна — уже опубликованные миграции пропускаются.
3. **Выберите режим обнаружения.** `balanced` (по умолчанию) подходит для большинства приложений; используйте `relaxed` для сайтов с большим объёмом контента, `strict` для поверхностей с высокими требованиями безопасности. Настройте с помощью `content_paths`, `safe_fields` и `min_confidence` — см. [Снижение ложных срабатываний](#reducing-false-positives).
4. **Проверьте региональные PII / пользовательские шаблоны.** Настройки по умолчанию ориентированы на Индию (Aadhaar, PAN, IFSC), а широкие числовые шаблоны (например, банковский счёт) могут совпадать с длинными числовыми идентификаторами вне маршрутов аутентификации. Замените или сократите `custom_patterns` для вашего региона и приложения, а маршруты с большим объёмом контента добавьте в `auth_paths` / `content_paths`.
5. **Включите хранение**, если ожидаете большой объём: `THREAT_DETECTION_RETENTION=true` (автоочистка через планировщик). Требует, чтобы планировщик Laravel (`schedule:run`) запускался через cron.
6. **Дополнительные опции, все отключены по умолчанию:** оповещения Slack (`THREAT_DETECTION_NOTIFICATIONS`), геообогащение (`php artisan threat-detection:enrich` — единственная функция, которая совершает исходящий вызов, к бесплатному ip-api.com), и запись через очередь (`THREAT_DETECTION_QUEUE` — включайте только если у вас уже запущен воркер очереди; в противном случае запись синхронна и не требует Redis).

Для базового обнаружения и логирования не требуются ни Redis, ни воркер очереди, ни исходящие сетевые вызовы.

---

## Снижение ложных срабатываний

Пакет предоставляет несколько инструментов для снижения ложных срабатываний. Используйте тот, который подходит вашей ситуации:

### Безопасные поля и безопасные пути

Исключите поле из сканирования полностью — либо по имени везде (`safe_fields`), либо по пути в точечной нотации для вложенного JSON (`safe_paths`). Самый простой подход и самый грубый — поле пропускается, поэтому обнаружение на нём вообще не выполняется.

Полные детали и примеры: [Безопасные поля](#safe-fields-false-positive-reduction).

### Подавление путей с контентом

Если у вас есть редакторы CMS, формы записей в блогах или секции комментариев, где пользователи отправляют насыщенный контент, такие пути часто вызывают ложные срабатывания (например, запись в блоге, содержащая примеры кода `<script>`). Добавьте эти пути, чтобы подавить предупреждения низкого/среднего уровня:```php
// config/threat-detection.php
'content_paths' => [
    'admin/posts/*',
    'admin/pages/*',
    'blog/*/edit',
    'comments',
],

На этих путях регистрируются только угрозы высокой степени серьёзности.

Сообщение о ложных срабатываниях

Нажмите кнопку FP на любой угрозе в панели управления, чтобы пометить её как ложное срабатывание. Это:

  1. Помечает угрозу как is_false_positive = true
  2. Автоматически создаёт правило исключения, чтобы похожие угрозы с того же URL/типа подавлялись в дальнейшем

Управляйте правилами исключений через API:```bash GET /api/threat-detection/exclusion-rules DELETE /api/threat-detection/exclusion-rules/{id}

### Оценка уверенности

Каждая угроза получает оценку уверенности (0–100) на основе:
- Количества совпадений с паттернами в одном запросе
- Критичности совпавшего паттерна
- Места обнаружения паттерна (строка запроса > заголовки > тело)
- Совпадения user-agent с известным инструментом атаки
- Текущего режима обнаружения

Угрозы ниже порога уверенности для вашего режима обнаружения не регистрируются (см. [Режимы обнаружения](#detection-modes)).

---

## Обнаруживаемые типы атак

| Категория | Примеры |
|----------|---------|
| **SQL-инъекции** | UNION, boolean, time-based, кодирование CHAR, DDL (DROP/ALTER/CREATE), DML (INSERT/UPDATE/DELETE), файловые операции (INTO OUTFILE, LOAD_FILE), перечисление ORDER BY, hex-строки, UNHEX |
| **NoSQL-инъекции** | Операторы MongoDB $ne, $gt, $regex, $where |
| **XSS** | Теги script, обработчики событий SVG (`<svg onload=`), HTML-обработчики событий (`<body onload=`, `<img onerror=`), CSS-выражения, JavaScript URI, манипуляции с DOM |
| **Выполнение кода** | RCE-шелл-функции, десериализация PHP, десериализация Java (base64 + hex magic bytes), инъекции шаблонов (Blade, JSP, ASP, Jinja2, Velocity), eval(), декодирование base64, PHP assert(), create_function(), preg_replace /e |
| **SSTI** | Математические проверки (`{{7*7}}`), import/config Jinja2, шаблоны Velocity, язык выражений |
| **Инъекции команд** | Linux (шелл-функции, цепочки команд, curl, wget, nc), Windows (cmd.exe, PowerShell, wscript, cscript, net user) |
| **Доступ к файлам** | Обход каталогов, протоколы LFI/RFI, проверки чувствительных файлов (.env, .git, composer.json) |
| **SSRF** | Localhost (127.0.0.1, 0.0.0.0, ::1), метаданные AWS/GCP, частные IP-адреса, hex/десятично закодированный localhost, DNS rebinding (xip.io, nip.io, sslip.io) |
| **LDAP-инъекции** | Манипуляции с LDAP-фильтрами, OR-инъекции |
| **XPath-инъекции** | Селекторы атрибутов, функции XPath (contains, substring) |
| **CRLF / инъекции заголовков** | URL-закодированный CRLF (`%0d%0a`), инъекции LF, инъекции нулевых байтов |
| **Протокольные атаки** | Контрабанда HTTP-запросов (CL+TE), SSI-инъекции |
| **Эксплойты CVE** | Shellshock (CVE-2014-6271), Spring4Shell (CVE-2022-22965), PHPUnit RCE (CVE-2017-9841), Drupalgeddon, Log4Shell |
| **Отслеживание зондов** | WordPress (`/wp-admin`, `/wp-login.php`), файлы конфигурации (`/.env`, `/.git`), инструменты баз данных (`/phpmyadmin`), технологические зонды (`.asp`, `.jsp`), Spring actuator, Swagger/API-документация — более 50 путей |
| **Сканеры** | SQLMap, Nikto, Nmap, Burp Suite, FeroxBuster, FFUF, XSStrike, Dalfox, Netsparker, Qualys, Nuclei и ещё более 20 (всего 53) |
| **AI-скраперы** | GPTBot, ClaudeBot, ChatGPT, ByteSpider, Cohere, Common Crawl |
| **Браузеры без головы** | HeadlessChrome, PhantomJS, Selenium, Puppeteer, Playwright |
| **Боты** | Python-скрипты, Go HTTP-клиенты, cURL, wget, AhrefsBot, SEMRushBot, пустые user-agent |
| **Аутентификация** | Обнаружение перебора, утечки токенов, раскрытие паролей, раскрытие идентификаторов сессий |
| **DDoS** | Обнаружение чрезмерных запросов на основе частоты |
| **Обход защиты** | Вставка SQL-комментариев, двойное URL-кодирование, кодирование HTML-сущностей, Unicode-экранирование, IIS Unicode, hex-экранирование |
| **Прочее** | GraphQL-интроспекция, загрязнение прототипов, открытые редиректы, XXE, веб-шеллы, криптомайнинг, обнаружение PII |

---

## Запуск набора тестов```bash
composer test

Пакет включает 335 тестов (856 утверждений), охватывающих паттерны обнаружения, поведение промежуточного ПО, конечные точки API, оценку уверенности, правила исключения, обнаружение DDoS, устойчивость к обходу, паттерны CVE, инъекции LDAP/XPath/SSTI, обнаружение ботов/сканеров, отслеживание зондов, команды экспорта, аутентификацию панели управления, безопасные поля, оптимизацию производительности и сквозную проверку HTTP-to-DB.


Лицензия

Лицензия MIT. Подробности см. в LICENSE.

Участие в разработке

Вклад приветствуется! Пожалуйста, отправьте Pull Request.

Авторы

Категории