Http 请求没有被 Nginx 服务器块捕获吗?

Http 请求没有被 Nginx 服务器块捕获吗?

我有一个只有一个站点配置(默认站点)的 nginx 服务器。

我在 access.log 中不断看到以下几行

xxx.xxx.xxx.xxx - - [10/Jul/2018:16:32:14 +0200] "GET / HTTP/1.1" 400 37 "-" "-"

我知道如果请求没有发送标Host:头,就会发生这种情况,例如curl -v -H "Host:" https://{{ server_ip }}

root@mypc:~# curl -v -H "Host:" http://{{ server_ip }}
* Rebuilt URL to: http://{{ server_ip }}/
*   Trying {{ server_ip }}...
* Connected to {{ server_ip }} ({{ server_ip }}) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 400 Bad Request
< Server: nginx/1.14.0 (Ubuntu)
< Date: Wed, 11 Jul 2018 08:14:07 GMT
< Content-Type: text/html
< Content-Length: 182
< Connection: close
<
<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.14.0 (Ubuntu)</center>
</body>
</html>
* Closing connection 0

我确实将我的网站配置为响应没有Host:标头的请求,错误代码为 444。显然,这不起作用。我认为我确实误解了文档,并且我的配置不正确。如果有人能指出缺少什么,我将非常高兴:

ssl_certificate /etc/letsencrypt/live/{{ hostname_fqdn }}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{{ hostname_fqdn }}/privkey.pem;

# Respond to requests without a host header with HTTP status 444
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name "";
    return 444;
}

server {
    listen 80;
    listen [::]:80;

    server_name {{ hostname_fqdn }};

    if ($allowed_country = no) {
        return 444;
    }

    return 301 https://{{ hostname_fqdn }}$request_uri;
}

server {
    listen 443 ssl;
    #listen [::]:443 ssl;

    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    server_name {{ hostname_fqdn }};

    if ($allowed_country = no) {
        return 444;
    }

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
    }

    location /static/ {
        root {{ django_static_root }};
    }
}

server {
    listen 80;
    listen [::]:80;

    listen 443 ssl;
    #listen [::]:443 ssl;

    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    server_name api.zeitschrift.hausbesitzerverlag.de;

    if ($allowed_country = no) {
        return 444;
    }

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
    }

    location /pmx-api/ {
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/htpasswd;

        limit_req zone=api burst=5;

        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
    }

    location /komtrigon-api/ {
        limit_req zone=api burst=5;

        include uwsgi_params;
        uwsgi_pass unix:/run/uwsgi/app/{{ django_project_name }}/socket;
    }

    location /static/ {
        root {{ django_static_root }};
    }
}

答案1

不带Host:在 HTTP/1.1(或更高版本)中无效,并且 nginx 正确地发送了 400 Bad Request 错误,甚至没有尝试使用任何 server块。来自RFC 7230 第 5.4 节

对于任何缺少 Host 标头字段的 HTTP/1.1 请求消息以及包含多个 Host 标头字段或具有无效字段值的 Host 标头字段的任何请求消息,服务器必须使用 400(错误请求)状态代码进行响应。

只有当请求使用古老的 HTTP/1.0 时,处理没有标头server的请求的块才会被命中。您可以使用命令行选项来模拟这种情况:Host:curl-0

curl -v -0 http://203.0.113.87/

从手册页中:

       -0, --http1.0
              (HTTP)  Tells  curl to use HTTP version 1.0 instead of using its
              internally preferred HTTP version.

答案2

初学者的错误。我忘了添加listen 443 ssl default_server;到第一个服务器块。

...

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    listen [::]:80 default_server;
    server_name "";
    return 444;
}

...

尽管 Micheal 对 RFC 的说法完全正确,但对于 nginx 的工作方式却并不正确,因为 nginx 没有内置功能可以在这种情况下返回 400。

它也没有具体回答我的问题。由于我的 Web 服务器 10 次中有 10 次收到没有主机标头的请求,这些请求都是由垃圾邮件发送者发送的,因此我决定忽略 RFC,直接关闭连接而不让垃圾邮件发送者知道 ( return 444;)。

答案3

我觉得你误解了一些事情。

我确实将我的网站配置为响应没有 Host: 标头的请求,错误代码为 444。显然,这不起作用。

你没有配置具体来说您的网站使用 来响应没有Host标头的请求444

它是:您配置您的站点,任何与块中的host其他值不匹配的值都将进入块。server_nameserverdefault_server

真正重要的是指令。您可以在块内default_server放置任何逻辑上无效的值。server_namedefault serverserver

https://nginx.org/en/docs/http/server_names.html

这个名称( )没有什么特别之处server_name "",它只是无数无效域名中的一个,与任何真实名称都不相交。其他无效名称(如“--”和“!@#”)同样可以使用。

相关内容