Назад | Перейти на главную страницу

Получаете ошибки BADREQ 400 на HaProxy?

Я получаю значительное количество записей BADREQ в моем журнале HAProxy (10+ в минуту).

Пример:

1 октября 19:46:00 LB haproxy [19022]: 69.171.251.8:57356 [01 / Oct / 2018: 19: 46: 00.903] имя сайта имя сайта / -1 / -1 / -1 / -1 / 5 400 187 - - ПРНН 19/19/0/0/5 0/0 ""

Кажется, что почти все они исходят от краулера Facebook.

Похоже, что поисковый робот по большей части нормально очищает контент. Однако небольшое количество этих запросов приводит к ошибкам BADREQ.

Как было предложено в другом месте, я использовал socat, чтобы увидеть последнюю ошибку, выполнив следующую команду:

sudo echo "show errors" | sudo socat unix-connect:/var/run/haproxy.stat stdio

Это дало мне следующий результат:

  invalid request
  backend mysite (#2), server <NONE> (#-1), event #127
  src 69.171.251.1:61042, session #9717, session flags 0x00000080
  HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
  HTTP chunk len 0 bytes, HTTP body len 0 bytes
  buffer flags 0x00808002, out 0 bytes, total 517 bytes
  pending 517 bytes, wrapping at 32776, error at position 0:

  00000  \x16\x03\x01\x02\x00\x01\x00\x01\xFC\x03\x03 B\x9B\xF8\xAE\xFB=\xD7dN
  00021+ \x8D\xAD\xCCP\x99\x9C\xEEow#w\n
  00033  \xB5\x99\x16g@\x1F{\x9A5H\x00\x00\xAA\xC00\xC0,\xC0(\xC0$\xC0\x14\xC0
  00057+ \n
  00058  \x00\xA5\x00\xA3\x00\xA1\x00\x9F\x00k\x00j\x00i\x00h\x009\x008\x007
  00080+ \x006\xCC\xA9\xCC\xA8\xCC\x14\xCC\x13\xCC\xAA\xCC\x15\x00\x88\x00\x87
  00098+ \x00\x86\x00\x85\xC02\xC0.\xC0*\xC0&\xC0\x0F\xC0\x05\x00\x9D\x00=\x005
  00120+ \x00\x84\xC0/\xC0+\xC0'\xC0#\xC0\x13\xC0\t\x00\xA4\x00\xA2\x00\xA0\x00
  00141+ \x9E\x00g\x00@\x00?\x00>\x003\x002\x001\x000\x00\x9A\x00\x99\x00\x98
  00164+ \x00\x97\x00E\x00D\x00C\x00B\xC01\xC0-\xC0)\xC0%\xC0\x0E\xC0\x04\x00
  00187+ \x9C\x00<\x00/\x00\x96\x00A\xC0\x12\xC0\x08\x00\x16\x00\x13\x00\x10
  00206+ \x00\r\xC0\r\xC0\x03\x00\n
  00214  \x00\xFF\x01\x00\x01)\x00\x00\x00\x14\x00\x12\x00\x00\x0Ffb.mysite.c
  00242+ om\x00\x0B\x00\x04\x03\x00\x01\x02\x00\n
  00254  \x00\x1C\x00\x1A\x00\x17\x00\x19\x00\x1C\x00\e\x00\x18\x00\x1A\x00\x16
  00272+ \x00\x0E\x00\r\x00\x0B\x00\x0C\x00\t\x00\n
  00284  \x00\r\x00 \x00\x1E\x06\x01\x06\x02\x06\x03\x05\x01\x05\x02\x05\x03
  00302+ \x04\x01\x04\x02\x04\x03\x03\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02
  00319+ \x033t\x00\x00\x00\x10\x00\x0B\x00\t\x08http/1.1\x00\x15\x00\xAE\x00
  00344+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00361+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00378+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00395+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00412+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00429+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00446+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00463+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00480+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00497+ \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
  00514+ \x00\x00\x00

Честно говоря, я понятия не имею, как разобраться в сказанном выше!

Обновление: мне удалось захватить трафик на порт 80 с помощью tcpdump. Я загрузил файл захвата и открыл его с помощью WinShark.

Я поймал несколько запросов с IP-адреса Facebook 31.13.127.5:

10622   15.837038   31.13.127.5 MYSERVERIP TCP  66  47658 → 80 [ACK] Seq=1 Ack=1 Win=61440 Len=0 TSval=1921577847 TSecr=59275252

10701   15.848790   31.13.127.5 MYSERVERIP TCP  583 47658 → 80 [PSH, ACK] Seq=1 Ack=1 Win=61440 Len=517 TSval=1921577859 TSecr=59275252

10702   15.848846   MYSERVERIP  31.13.127.5 HTTP    253 HTTP/1.0 400 Bad request  (text/html)

10914   15.927603   31.13.127.5 MYSERVERIP  TCP 66  47658 → 80 [FIN, ACK] Seq=518 Ack=189 Win=63488 Len=0 TSval=1921577937 TSecr=59275274

10915   15.927611   MYSERVERIP  31.13.127.5 TCP 66  80 → 47658 [ACK] Seq=189 Ack=519 Win=30080 Len=0 TSval=59275294 TSecr=1921577937

12044   17.419319   31.13.127.5 MYSERVERIP  TCP 74  53712 → 80 [SYN] Seq=0 Win=61320 Len=0 MSS=1460 SACK_PERM=1 TSval=1921579431 TSecr=0 WS=2048

12045   17.419337   MYSERVERIP  31.13.127.5 TCP 74  80 → 53712 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1460 SACK_PERM=1 TSval=59275667 TSecr=1921579431 WS=128

12125   17.493182   31.13.127.5 MYSERVERIP  TCP 66  53712 → 80 [ACK] Seq=1 Ack=1 Win=61440 Len=0 TSval=1921579505 TSecr=59275667

12126   17.501269   31.13.127.5 MYSERVERIP  TCP 583 53712 → 80 [PSH, ACK] Seq=1 Ack=1 Win=61440 Len=517 TSval=1921579513 TSecr=59275667

12127   17.501387   MYSERVERIP  31.13.127.5 HTTP    253 HTTP/1.0 400 Bad request  (text/html)

12179   17.576974   31.13.127.5 MYSERVERIP  TCP 66  53712 → 80 [FIN, ACK] Seq=518 Ack=189 Win=63488 Len=0 TSval=1921579589 TSecr=59275687

В этом журнале вы видите приветственное сообщение клиента TLS.

Это начальное сообщение, отправленное клиентом для инициирования согласования, следовательно, в этом сообщении нет ничего зашифрованного. Вы заметите, что в этом сообщении есть два поля, содержащих текст. Это поля следующего протокола: SNI (указание имени сервера) и ALPN (согласование протокола прикладного уровня). Остальная часть сообщения представляет собой двоичные данные, поэтому их не так легко читать.

На этой ранней стадии TLS протокол прикладного уровня еще не согласован, и ключи сеанса не установлены. Клиент даже не получил сертификат, который он мог бы проверить. Это означает, что клиент еще не может отправить какой-либо HTTP-запрос, а при отсутствии HTTP-запроса нет ничего, на что можно было бы отправить код состояния в ответ.

Запись в журнале определенно звучит так, будто HAProxy думает, что отвечает на HTTP-запрос, даже если он не был отправлен.

Исходя из этого, похоже, что здесь происходит то, что сервер говорит HTTP, а клиент говорит HTTPS. Таким образом, сообщение приветствия клиента TLS неправильно интерпретируется как HTTP-запрос и отклоняется как недействительное.

Вам было бы полезно захватывать трафик, чтобы его можно было проверить, чтобы узнать, что на самом деле отправляется по сети. Если я прав относительно сказанного выше, вы должны увидеть сообщение TLS Client Hello, которое можно декодировать с помощью Wireshark (или аналогичного), и незашифрованный HTTP-ответ с кодом ошибки 400.

Что также будет интересно в этом захвате пакета, так это номер порта.

Вы можете увидеть, что могло произойти, если пользователь ввел URL-адрес с протоколом и номером порта, например https://example.com:80/ и facebook пытается получить этот URL несколько раз (поскольку он продолжает терпеть неудачу).

Я сам попытался поместить такой искаженный URL в facebook, и конечно же facebook отправил сообщение Client Hello на порт 80. Мой (Apache) веб-сервер ответил кодом состояния 400, как и ожидалось.

Захват вашего пакета подтверждает, что трафик в вашем случае также происходит через порт 80. Предположительно, кто-то дал facebook URL-адрес https, указывающий на ваш сайт и заменив вместо этого правильный номер порта на 80.

Ваш сервер правильно отвечает кодом 400, и facebook понимает, что получение URL-адреса не удалось. Исправлять нечего. Ваш сервер работает как задумано, и единственной проблемой была ошибка пользователя при вводе URL-адреса в facebook.

Можно узнать немного больше о неверном URL-адресе, если ваш сервер автоматически определит протокол, чтобы поддерживать как HTTP, так и HTTPS на одном и том же порту. Однако я бы не рекомендовал такие хаки, и я не знаю, поддерживает ли это какое-либо программное обеспечение веб-сервера.