Если просмотреть access.log nginx на сервере с открытым портом 80, в нём найдутся странные строки: вместо GET / HTTP/1.1 там \x16\x03\x01\x02\x00\x01 и ответ 400. Это не сбой и не взлом nginx, а сканеры, которые проверяют, какие протоколы слушает ваш сервер. Разберём, что значат эти байты, кого стоит банить и почему пустые запросы и запросы без User-Agent банить нельзя.
Откуда в журнале байты
nginx ждёт на HTTP-порту текстовый запрос. Если вместо него приходит что-то другое, он отвечает 400 Bad Request и записывает в журнал то, что получил. Непечатаемые байты при этом экранируются как \xHH. Первые байты обычно однозначно выдают протокол, которым пытались говорить с сервером.
Что означают типичные строки
| Начало запроса в журнале | Что это |
|---|---|
\x16\x03\x01... | TLS ClientHello: HTTPS-запрос на HTTP-порт. 0x16 — тип записи «рукопожатие», 0x03 0x01 — версия TLS в заголовке записи. |
\x00\x00\x00\x85\xFFSMB... или ...\xFESMB | Проба SMB, протокола файловых шар Windows. Ищут открытые шары и уязвимые версии. |
\x03\x00\x00/*\xE0...Cookie: mstshash= | Начало подключения RDP. Сканер проверяет, не висит ли удалённый рабочий стол на этом порту. |
\x05\x01\x00 или \x04\x01... | Приветствие SOCKS5 или SOCKS4. Ищут открытые прокси, чтобы ходить через них. |
SSH-2.0-Go | Клиент SSH на HTTP-порту. |
Так выглядят эти строки в журнале (адреса заменены на тестовые):
198.51.100.23 - - [09/Oct/2026:02:14:07 +0300] "\x16\x03\x01\x02\x00\x01\x00\x01\xFC\x03\x03" 400 157 "-" "-"
198.51.100.41 - - [09/Oct/2026:02:31:55 +0300] "\x03\x00\x00/*\xE0\x00\x00\x00\x00\x00Cookie: mstshash=Administr" 400 157 "-" "-"
203.0.113.77 - - [09/Oct/2026:03:02:19 +0300] "\x05\x01\x00" 400 157 "-" "-"
\x16\x03 иногда бывает и от живого клиента, у которого в настройках перепутан порт, например https://site:80. Но живой клиент повторяет ошибку пару раз и уходит, а сканер приходит с новым набором проб.
Сколько этого на реальных серверах
Анализ журналов KIPBan за сутки на 9 октября 2026 года нашёл мусор вместо HTTP-запроса на 7 серверах из 13: 3 319 запросов от 160 адресов. 155 из этих адресов не были заблокированы ничем, хотя на части серверов fail2ban настраивал опытный администратор. Готового фильтра для таких запросов в поставке fail2ban нет, поэтому их обычно никто не ловит.
Чего банить нельзя
Рядом с мусорными запросами в журнале есть строки, которые очень хочется забанить заодно. Делать этого не нужно:
- Пустой запрос (
"" 400). Клиент открыл соединение и закрыл его, ничего не отправив. Так делают проверки доступности, балансировщики и браузеры, которые заранее открывают соединение «про запас» и не используют его. - Запрос без User-Agent (
"-"в последнем поле). Так ходят мониторинг, вебхуки, платёжные уведомления и клиенты API. Отсутствие User-Agent ничего не говорит об атаке. - curl, Wget, python-requests в User-Agent. Это те же мониторинг и интеграции. Шаблоны KIPBan их не блокируют.
Правило «банить всё с кодом 400» поймает всех перечисленных. Банить стоит только запросы, которые начинаются с байтов чужого протокола.
Фильтр для fail2ban
Простой фильтр для журнала nginx в формате combined, который ловит TLS, SOCKS, RDP и SMB на HTTP-порту:
# /etc/fail2ban/filter.d/nginx-binary.conf
[Definition]
failregex = ^<HOST> \S+ \S+ \[[^\]]*\] "\\x(?:16\\x03|05\\x01|04\\x01|03\\x00\\x00|00\\x00\\x00)
ignoreregex =
# /etc/fail2ban/jail.d/nginx-binary.local
[nginx-binary]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 1
findtime = 10m
action = dummy
Перед включением проверьте его на своём журнале и посмотрите, кто попадает:
fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-binary.conf --print-all-matched
Строка action = dummy включает режим наблюдения: jail считает, кого забанил бы, но ничего не блокирует. Как его читать и когда переключать на бан, описано в статье «Режим наблюдения: как включить jail и не забанить своих».
Фильтр рассчитан на журнал, где IP посетителя стоит в начале строки. Если сайт за Cloudflare или другим прокси, сначала настройте запись реального IP, иначе забаните прокси. Подробнее в статье «fail2ban за Cloudflare».
Как это сделано в KIPBan
В каталоге KIPBan есть шаблон «Мусор вместо HTTP-запроса»: TLS на HTTP-порт, пробы SMB, RDP, SOCKS, SSH и двоичный мусор, порог 1. Пустые запросы и запросы без User-Agent он не трогает. Анализ журналов сам находит журналы nginx и Apache на сервере, в том числе в папках панели управления, и показывает, сколько таких адресов приходит и сколько из них уже заблокировано. Jail с этим шаблоном включается кнопкой из отчёта и сначала работает в режиме наблюдения.
Анализ журналов работает на Linux с агентом KIPBan 21.5 и новее, а журналы не покидают сервер: в кабинет приходят только счётчики.
Вопросы
Что значит \x16\x03\x01 в access.log nginx?
Это начало TLS-рукопожатия: кто-то отправил HTTPS-запрос на HTTP-порт. Чаще всего это сканер, который проверяет протоколы на всех портах подряд, реже клиент с неверно указанным портом. nginx отвечает на такой запрос кодом 400.
Можно ли банить запросы без User-Agent?
Нет. Без User-Agent ходят мониторинг, вебхуки, платёжные уведомления и клиенты API. Отсутствие User-Agent не признак атаки, и такой бан сломает интеграции.
Почему в access.log пустые запросы с кодом 400?
Клиент открыл соединение и закрыл его, ничего не отправив. Так делают проверки доступности, балансировщики и браузеры, которые открывают соединение заранее. Банить такие адреса нельзя.