El servidor web Nginx tiene un maravilloso código de respuesta 444 que "cierra" la conexión sin enviar datos. Esta funcionalidad es muy útil para filtrar tráfico espurio: si estamos seguros de que el cliente no es válido según algunos criterios, no hay necesidad de notificarlo, por ejemplo, con la respuesta número 403. Es más eficiente simplemente detener la transferencia de datos, que, a menudo, puede reducir significativamente la carga en el servidor.
Las recomendaciones para usar tales respuestas se pueden encontrar en todas partes en las instrucciones sobre el bloqueo de clics en enlaces de sitios populares y el spam de referencia, la protección contra DDoS, etc.
Y, en general, a lo largo de los años, estos consejos podrían usarse casi sin mirar, pero ... los navegadores modernos no se detienen y periódicamente nos presentan nuevas sorpresas.
Programa obligatorioServidor:$ 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 (versión oficial), (64 bits)
Firefox Quantum 61.0 (64 bits)
Tomé por experiencia solo los navegadores Chrome y Firefox. No porque el resto no tenga pecado, solo el comportamiento descrito a continuación fue bastante estable en los dos.
Entonces, tenemos un sitio web y queremos restringir el acceso a la ubicación sin condiciones y sin transmitir ningún dato:
server { ... location = /code/444 { return 444; } ... }
En espera:
- el navegador enviará una solicitud;
- el servidor recibirá una solicitud, cerrará la conexión y escribirá una línea con el código 444 en el registro;
- al no recibir datos, el navegador mostrará un error y dejará de comunicarse con el servidor.
Para mayor claridad, mostramos nuestras expectativas con la línea de registro 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"
Realidad de 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"
Chrome envió una solicitud, no recibió una respuesta, inmediatamente envió otra solicitud, después de lo cual comenzó a verificar periódicamente la disponibilidad del sitio.
Realidad de 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"
Firefox decidió no ser mezquino e inmediatamente envió 20 solicitudes (a veces 10). Pero luego no hace ningún "chequeo".
Al mismo tiempo, informa en el depurador como para una solicitud:
Por lo tanto, esperando recibir una solicitud del cliente, de hecho, recibimos 3-20 solicitudes. Además de las llamadas que son completamente innecesarias para nosotros, existe el riesgo de alimentar dicho registro, por ejemplo, a un script anti-DDoS y bloquear esta ip. Y parecería la mitad del problema, porque ya "le dimos" 444, es decir, no sentimos pena por él, pero puede suceder al revés: le mostraremos al cliente lo que no planeamos en absoluto.
Modificar la configuración:
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"; } ... }
Aquí hemos prohibido la entrega de contenido a todos los clientes con un referente "
https://habr.com/post/415565/
"al cambiar a la página
tison.ru/codeif/444En espera:
Conociendo las características ya descritas anteriormente, asumimos que los navegadores harán más de una solicitud, pero no recibirán la respuesta número 200 del servidor.
En forma de registro, nuevamente, esperamos una o más líneas del formulario:
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"
Al depurar en la consola, todo funciona como se esperaba. El servidor cerró la conexión y no recibimos contenido:
$ curl --referer "https://habr.com/post/415565/" tison.ru/codeif/444 curl: (52) Empty reply from server
Bueno, la realidad del navegador.
Cromo:
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"
Después de hacer varias solicitudes de solicitud "honestas", ambos navegadores descartaron la referencia y mostraron con calma la página bloqueada. Firefox, sin embargo, no siempre hace esto. En mis pruebas, ~ en el 15% de las solicitudes, lo que ayuda aún más en el análisis.
Este comportamiento se ha observado durante mucho tiempo, pero cuando exactamente Chrome y Firefox cambiaron a este modo de operación, no puedo decirlo. Sin embargo, también, y cuánto tiempo funcionará este modo.
Entonces, el uso de
return 444 no siempre producirá los resultados esperados. Bueno, mañana, esperamos ver a más desarrolladores de navegadores complacernos.