Por que (hoje) o retorno 444 nem sempre é útil

O servidor da web Nginx possui um maravilhoso código de resposta 444 que "fecha" a conexão sem enviar dados. Essa funcionalidade é muito útil na filtragem de tráfego espúrio - se tivermos certeza de que o cliente não é válido por alguns critérios, não será necessário notificá-lo, por exemplo, com a 403ª resposta. É mais eficiente simplesmente parar a transferência de dados, o que, muitas vezes, pode reduzir significativamente a carga no servidor.

Recomendações para o uso de tais respostas podem ser encontradas em qualquer lugar nas instruções sobre o bloqueio de cliques em links de sites populares e spam de referência, proteção contra DDoS, etc.

E, em geral, ao longo dos anos, essas dicas podem ser usadas quase sem olhar, mas ... os navegadores modernos não param e periodicamente nos apresentam novas surpresas.

Programa obrigatório
Servidor:

$ uname -orm FreeBSD 11.1-STABLE amd64 

 $ nginx -v nginx version: nginx/1.15.0 

Cliente:

 >ver Microsoft Windows [Version 10.0.15063] 

Google Chrome 67.0.3396.99 (versão oficial), (64 bits)
Firefox Quantum 61.0 (64 bits)

Peguei por experiência apenas os navegadores Chrome e Firefox. Não porque os demais não tenham pecado, apenas o comportamento descrito abaixo foi bastante estável nos dois.

Portanto, temos um site e queremos restringir o acesso ao local sem quaisquer condições e sem transmitir dados:

 server { ... location = /code/444 { return 444; } ... } 

Aguardando:

  • o navegador enviará uma solicitação;
  • o servidor receberá uma solicitação, feche a conexão e escreva uma linha com o código 444 no log;
  • não recebendo dados, o navegador exibirá um erro e interromperá a comunicação com o servidor.

Para maior clareza, mostramos nossa expectativa com a linha de log Nginx:

 18.12.12.29 - - [28/Jun/2018:11:50:10 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 

Realidade do Chrome:

 18.12.12.29 - - [28/Jun/2018:11:50:10 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 18.12.12.29 - - [28/Jun/2018:11:50:10 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 18.12.12.29 - - [28/Jun/2018:11:50:15 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 18.12.12.29 - - [28/Jun/2018:11:52:04 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 

O Chrome enviou uma solicitação, não recebeu uma resposta, enviou imediatamente outra solicitação, após a qual começou a verificar periodicamente o site quanto à disponibilidade.

Realidade do Firefox:

 18.12.12.29 - - [28/Jun/2018:12:34:38 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:38 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:38 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:38 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:38 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:39 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:39 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:39 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:39 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:39 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:39 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:40 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:40 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:40 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:40 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:40 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:41 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:41 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:41 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:34:41 +0000] "GET /code/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 

O Firefox decidiu não ser mesquinho e imediatamente enviou 20 solicitações (às vezes 10). Mas então ele não faz nenhum "cheque".

Ao mesmo tempo, ele relata no depurador como para uma solicitação:

Título de spoiler
imagem

Assim, esperando receber uma solicitação do cliente, na verdade, temos de 3 a 20 solicitações. Além de chamadas totalmente desnecessárias para nós, existe o risco de alimentar esse log, por exemplo, com um script anti-DDoS e bloquear esse ip. E isso pareceria metade do problema, porque já "demos" 444 a ele, ou seja, não sentimos pena dele, mas isso pode acontecer ao contrário - mostraremos ao cliente o que não planejamos.

Modifique a configuração:

 map $http_referer $code_if { "~*https://habr.com/post/415565/" 1; "http://tison.ru/ref" 1; default 0; } ... server { ... location = /code/444 { return 444; } ... location = /codeif/444 { if ( $code_if = 1 ) { return 444; } add_header "Content-Type" "text/html; charset=UTF-8" always; return 200 "Expected code 444"; } ... } 

Aqui proibimos a entrega de conteúdo a todos os clientes com um referenciador "
https://habr.com/post/415565/ "ao mudar para a página tison.ru/codeif/444

Aguardando:

Conhecendo os recursos já descritos acima, assumimos que os navegadores farão mais de uma solicitação, mas não receberão a 200ª resposta do servidor.

Na forma de um log, novamente, esperamos uma ou mais linhas do formulário:

 18.12.12.29 - - [28/Jun/2018:12:52:02 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 

Ao depurar no console, tudo funciona como esperado. O servidor encerrou a conexão e não recebemos conteúdo:

 $ curl --referer "https://habr.com/post/415565/" tison.ru/codeif/444 curl: (52) Empty reply from server 

Bem, a realidade do navegador.

Chrome:

 18.12.12.29 - - [28/Jun/2018:12:58:12 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 18.12.12.29 - - [28/Jun/2018:12:58:12 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 18.12.12.29 - - [28/Jun/2018:12:58:13 +0000] "GET /codeif/444 HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 

Firefox:

 18.12.12.29 - - [28/Jun/2018:12:56:29 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:29 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:29 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:29 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:30 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:30 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:30 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:30 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:30 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:30 +0000] "GET /codeif/444 HTTP/1.1" 444 0 "http://tison.ru/ref" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:31 +0000] "GET /codeif/444 HTTP/1.1" 200 17 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 18.12.12.29 - - [28/Jun/2018:12:56:31 +0000] "GET /favicon.ico HTTP/1.1" 200 6782 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0" 

Após fazer várias solicitações "honestas", os dois navegadores abandonaram o referenciador e exibiram calmamente a página sendo bloqueada. O Firefox, no entanto, nem sempre faz isso. Nos meus testes, ~ em 15% dos pedidos, o que ajuda ainda mais na análise.

Esse comportamento é observado há muito tempo, mas quando exatamente o Chrome e o Firefox mudaram para esse modo de operação, não sei dizer. No entanto, e por quanto tempo esse modo funcionará.

Portanto, hoje, o uso do retorno 444 nem sempre produz os resultados esperados. Bem, amanhã, esperamos ver mais desenvolvedores de navegadores, por favor.

Source: https://habr.com/ru/post/pt415565/


All Articles