Как обнаружить атаки SQL-инъекций в логах веб-сервера

В прошлой статье мы говорили про анализ логов как ежедневную привычку. Сегодня я покажу, как эту привычку превратить в конкретный инструмент для охоты за SQL-инъекциями.

Я покажу четыре уровня защиты — от простого grep до машинного обучения. Вы сможете выбрать то, что подходит именно под ваш проект.

Теория: что мы ищем в логах

Прежде чем писать скрипты, давайте поймём, как SQL-инъекция выглядит в запросе к серверу.

Злоумышленник пытается подменить параметр запроса так, чтобы он стал частью SQL-команды. Классика:

sql SELECT * FROM users WHERE username = 'admin' OR '1'='1' -- и пароль не нужен

В логе веб-сервера это будет выглядеть как-то так:

192.168.1.100 - - [20/Nov/2025:08:42:15 +0300] "GET /login?user=admin'+OR+'1'%3D'1'&pass=123 HTTP/1.1" 200 5324

Обратите внимание на URL-кодирование: %3D — это знак равенства, ' — апостроф. Наша задача — распознать такие паттерны .

Уровень 1: Ручной grep (экспресс-диагностика)

Самый быстрый способ понять, атакуют ли вас прямо сейчас — пройтись по логам классическим grep"ом.

Вот набор выражений, которые я держу под рукой:

```bash

Базовые SQL-инъекции (OR, UNION, SELECT)

grep -iE "(\%27)|(--)|(\%23)|(select.from)|(union.select)" /var/log/nginx/access.log

Попытки обхода авторизации

grep -iE "(\%27\%20OR\%20)|(\'\%20OR\%20)|('\%7C\%7C')" /var/log/nginx/access.log

Запросы к системным таблицам

grep -iE "(information_schema|mysql.|pg_|sqlite_)" /var/log/nginx/access.log

Функции для эксплуатации

grep -iE "(xp_cmdshell|exec master|exec xp|pg_sleep|waitfor delay|benchmark)" /var/log/nginx/access.log ```

Важно: Это только для первичного анализа. На проде такое лучше не гонять — тяжело и глазами читать сотни строк — то ещё удовольствие.

Уровень 2: Python-скрипт с регулярками

Для регулярного анализа я использую небольшие Python-утилиты. Они парсят лог построчно и бьют тревогу при совпадении с паттернами .

Вот упрощённая версия того, что реально работает у меня:

```python

!/usr/bin/env python3

import re import sys from collections import defaultdict from datetime import datetime

class SQLiDetector: def init(self, threshold=5): self.threshold = threshold self.suspicious_ips = defaultdict(int)

    # Регулярки для разных СУБД
    self.patterns = [
        # MySQL/MariaDB
        (r"(?i)(union.*select.*from|select.*from.*where.*=.*'|information_schema\.tables)", "MySQL"),
        # PostgreSQL
        (r"(?i)(pg_sleep|cast\(.*as.*\)|pg_|::text|::int)", "PostgreSQL"),
        # MSSQL
        (r"(?i)(xp_cmdshell|exec master|waitfor\s+delay|sp_executesql)", "MSSQL"),
        # Oracle
        (r"(?i)(dbms_pipe|utl_http|utl_file|ctxsys\.)", "Oracle"),
        # Универсальные
        (r"(\%27|\'|\-\-|%23|#)", "SQL метасимволы"),
        (r"(?i)(or\s+1=1|or\s+true|or\s+\d+=\d+|and\s+1=1)", "Логические операторы"),
        (r"(?i)(order\s+by\s+\d+|group\s+by\s+\d+|having\s+\d+=\d+)", "Перебор колонок"),
    ]

def analyze_line(self, line):
    """Анализ одной строки лога"""
    # Типичный формат: IP - - [date] "method url" status size
    match = re.match(r'(\d+\.\d+\.\d+\.\d+).*?"(?:GET|POST)\s+(\S+).*?"\s+(\d+)', line)
    if not match:
        return None

    ip, url, status = match.groups()

    # Декодируем URL
    import urllib.parse
    url = urllib.parse.unquote(url)

    # Проверяем паттерны
    for pattern, db_type in self.patterns:
        if re.search(pattern, url):
            self.suspicious_ips[ip] += 1
            return {
                'timestamp': datetime.now().isoformat(),
                'ip': ip,
                'url': url,
                'status': status,
                'pattern': db_type,
                'matched': pattern
            }
    return None

def main(): detector = SQLiDetector()

# Читаем лог из stdin или файла
if len(sys.argv) > 1:
    f = open(sys.argv[1], 'r')
else:
    f = sys.stdin

alerts = []
for line in f:
    result = detector.analyze_line(line)
    if result:
        alerts.append(result)
        print(f"[ALERT] {result['timestamp']} - {result['ip']} пытается {result['pattern']}: {result['url'][:100]}")

        # Если IP превысил порог — бьём тревогу громче
        if detector.suspicious_ips[result['ip']] > detector.threshold:
            print(f"*** ВНИМАНИЕ! IP {result['ip']} превысил порог подозрительной активности!")

if len(sys.argv) > 1:
    f.close()

print(f"\nИтого: {len(alerts)} подозрительных запросов")
for ip, count in detector.suspicious_ips.items():
    if count > 0:
        print(f"{ip}: {count}")

if name == "main": main() ```

Этот скрипт не только ищет паттерны, но и считает количество подозрительных запросов с одного IP. Если их больше порога — пора бить в колокола .

Запускать можно так:

bash cat /var/log/nginx/access.log | python3 sqli_detector.py

Уровень 3: Elasticsearch и готовые правила

Если у вас уже настроен ELK-стек, изобретать велосипед не надо. Elastic Security предлагает готовые правила для обнаружения SQL-инъекций .

Вот как выглядит реальное правило от Elastic (EQL-запрос):

eql any where url.original like~ ( "*%20order%20by%*", "*waitfor%20delay%20*", "*%28select%20*from%20pg_sleep%285*", "*union*select*", "*or*1=1*", "*into%20outfile*", "*load_file%28*", "*@@version*", "*information_schema.tables*" )

Правило мониторит индексы logs-nginx.access-*, logs-apache.access-*, logs-iis.access-* и срабатывает при совпадении с любым из паттернов .

Уровень 4: Машинное обучение (для тех, кому мало)

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

Здесь на помощь приходит машинное обучение.

Что говорит наука

Недавнее исследование на Nginx-логах (1.65 миллиона записей) показало впечатляющие результаты :

| Алгоритм | Точность | F1-score | AUC | |----------|----------|----------|-----| | Random Forest | 99.92% | 99.94% | 0.9994 | | SVM | 96.45% | — | — |

Другое исследование подтверждает: Random Forest даёт точность 97.58% при обнаружении SQL-инъекций в сетевых логах .

Как это внедрить

Полноценный ML-пайплайн — задача нетривиальная. Но если хочется попробовать, вот roadmap:

  1. Сбор данных. Нужен датасет с размеченными логами (нормальные запросы и атаки).
  2. Извлечение признаков. Превращаем строки запросов в числа:
  3. Длина запроса
  4. Количество специальных символов
  5. Наличие ключевых слов
  6. Энтропия строки
  7. Обучение модели. Random Forest отлично работает "из коробки".
  8. Интеграция. Модель должна получать поток логов и классифицировать их в реальном времени.

В KNIME (платформа для data science) есть готовые компоненты для такого пайплайна .

Интеграция: от логов к алертам

Обнаружить атаку — полдела. Нужно ещё правильно на неё среагировать.

Вот как выглядит типовой процесс :

  1. Сбор. Логи стекаются в центральное хранилище (ELK, Tencent Cloud CLS, Aliyun).
  2. Анализ. Применяются правила (регулярки или ML).
  3. Обогащение. К IP подтягивается информация из threat intelligence (известные плохие адреса, геолокация).
  4. Корреляция. Событие связывается с другими активностями (например, был ли до этого брутфорс).
  5. Алерт. Если всё сходится — уведомление в Telegram, Slack или по почте.
  6. Блокировка. Можно автоматически добавить IP в firewall или WAF.

Практические рекомендации

На основе своего опыта и анализа источников , вот что я советую:

1. Включите детальное логирование

В MySQL: sql SET GLOBAL general_log = 'ON'; SET GLOBAL log_output = 'TABLE';

Но осторожно: на продакшене это может убить производительность. Лучше использовать специализированные инструменты вроде Database Audit .

2. Используйте WAF

Хороший WAF (Cloudflare, AWS WAF, Tencent Cloud WAF) отсечёт большинство примитивных атак ещё на подступах. В логах останется только то, что реально заслуживает внимания .

3. Смотрите не только на запросы, но и на ответы

Иногда атаку видно не по запросу, а по ответу сервера: - Неожиданно большие объёмы данных - Необычные статусы (200 на запрос с явной инъекцией) - SQL-ошибки в теле ответа

4. Автоматизируйте рутину

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

Чек-лист для внедрения

Если вы хотите системно подойти к вопросу, вот что нужно сделать:

  • [ ] Настроить централизованный сбор логов (ELK, Graylog, облачный сервис)
  • [ ] Добавить базовые правила обнаружения (из этой статьи или готовые из Elastic)
  • [ ] Настроить алерты в рабочий канал
  • [ ] Раз в неделю просматривать статистику и подкручивать правила под свой проект
  • [ ] Для критичных систем — рассмотреть внедрение ML-детекции или коммерческого SIEM

Вместо заключения

Обнаружение SQL-инъекций по логам — это как игра в детектива. Сначала вы ищете очевидные улики (OR 1=1), потом учитесь замечать мелкие несоответствия, а со временем начинаете предсказывать, где и когда преступник нанесёт следующий удар.

Начинайте с малого. Поставьте простой Python-скрипт, который раз в день прогоняет логи и шлёт отчёт в Telegram. Когда привыкнете к этому уровню осознанности, захочется большего — тогда и перейдёте на ELK с машинным обучением.

Главное — не останавливаться на достигнутом. Атаки становятся сложнее, но и наши инструменты не стоят на месте.