Django错误:无效的HTTP_HOST标头:u'/ run/myprojectname/gunicorn.sock:'

Dan*_*inn 19 django http nginx

我知道在SO上有很多这样的问题,但它们似乎都没有回答我的特定问题.

据我所知,Django的ALLOWED_HOSTS价值是阻止任何80没有适当Host:值的IP 端口请求,并且当请求进入时没有正确的值时,Django会给我发电子邮件.我也知道光滑的Nginx黑客会让这个问题消失,但我试图了解一个这样的请求的性质,并确定这是否是一个我需要担心的安全问题.

这些请求是有道理的:

[Django] ERROR: Invalid HTTP_HOST header: '203.0.113.1'.  You may need to add u'203.0.113.1' to ALLOWED_HOSTS.
Run Code Online (Sandbox Code Playgroud)

但是这一种让我感到害怕:

[Django] ERROR: Invalid HTTP_HOST header: u'/run/my_project_name/gunicorn.sock:'.
Run Code Online (Sandbox Code Playgroud)

这是不是意味着请求者发送Host: /run/my_project_name/gunicorn.sock到服务器?如果是这样,他们如何拥有我的.sock文件的路径名?我的服务器是否以某种方式泄露了这些信息?

另外,当我正在运行Django 1.6.5时,我不明白为什么我收到这些电子邮件,因为这张票已被标记固定一段时间了.

有人可以解释我所缺少的东西吗?

这是我的settings.LOGGING变量:

{
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {'()': 'django.utils.log.RequireDebugFalse'}
    },
    'formatters': {
        'simple': {'format': '%(levelname)s %(message)s'},
        'verbose': {'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'}
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
            'level': 'DEBUG'
        },
        'mail_admins': {
            'class': 'django.utils.log.AdminEmailHandler',
            'filters': ['require_debug_false'],
            'level': 'ERROR'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True
        },
        'my_project_name': {
            'handlers': ['console'], 
            'level': 'DEBUG'
        }
    },
    'version': 1
}
Run Code Online (Sandbox Code Playgroud)

这是我的nginx配置:

worker_processes 1;
pid /run/nginx.pid;
error_log /var/log/myprojectname/nginx.error.log debug;
events {
}
http {
  include mime.types;
  default_type application/octet-stream;
  access_log /var/log/myprojectname/nginx.access.log combined;
  sendfile on;
  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/html text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;
  upstream app_server {
    server unix:/run/myprojectname/gunicorn.sock fail_timeout=0;
  }
  server {
    listen 80 default;
    listen [::]:80 default;
    client_max_body_size 4G;
    server_name myprojectname.mydomain.tld;
    keepalive_timeout 5;
    root /var/www/myprojectname;
    location / {
      try_files $uri @proxy_to_app;
    }
    location @proxy_to_app {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $host;
      proxy_redirect off;
      proxy_pass http://app_server;
    }
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /tmp;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

最后,我在我的nginx访问日志中找到了这个.它对应于抱怨/run/myprojectname/gunicorn.sock是无效的HTTP_HOST标头的电子邮件.*

当然,这一切都在一条线上:

2014/09/05 20:38:56 [info] 12501#0: *513 epoll_wait() reported that client
prematurely closed connection, so upstream connection is closed too while sending
request to upstream, client: 54.84.192.68, server: myproject.mydomain.tld, request:
"HEAD / HTTP/1.0", upstream: "http://unix:/run/myprojectname/gunicorn.sock:/"
Run Code Online (Sandbox Code Playgroud)

显然我仍然不知道这意味着什么:-(

  • 更新#1:添加了我的settings.LOGGING
  • 更新#2:添加了我的nginx配置
  • 更新#3:从我的nginx日志中添加了一条有趣的行
  • 更新#4:更新了我的nginx配置

use*_*130 23

似乎

proxy_set_header Host $http_host
Run Code Online (Sandbox Code Playgroud)

应改变

proxy_set_header Host $host
Run Code Online (Sandbox Code Playgroud)

server_name 应适当设置为用于访问服务器的地址.如果你想要它全部捕获,你应该使用server_name www.domainname.com ""(doc here).

我不确定,但我认为如果客户端没有发送Host:标题,你会看到的是什么.由于nginx没有收到任何Host:标题,因此没有Host:标题传递给gunicorn.在这一点上,我认为gunicorn填充Host:作为套接字路径并告诉Django这是因为这是使用的连接.使用$host和设置server_namein nginx应确保Host:正确传递给gunicorn并解决此问题.

至于电子邮件,根据您链接的票证中的提交,看起来仍然会为不允许的主机发送电子邮件.添加到文档也是一种建议的方法来禁用正在发送的电子邮件:

    'loggers': {
        'django.security.DisallowedHost': {
        'handlers': ['null'],
        'propagate': False,
    },
Run Code Online (Sandbox Code Playgroud)

  • 这听起来似乎有道理,但我想测试这样的请求,看看我是否可以重现它。运行 `curl 203.0.113.1` 当前会产生一封声称 203.0.113.1 是无效主机标头的电子邮件,而 `curl 203.0.113.1 -H 'Host:'` 导致根本没有邮件。你能解释一下我如何重现给我那封 gunicorn 电子邮件的请求吗? (2认同)

Ern*_*mbe 11

我发现一些评论表明抑制电子邮件并不是一个好主意,因为它没有直接解决问题.我发现最有效的解决方案是将以下内容添加到您的nginx设置中:

server {

    ...

    ## Deny illegal Host headers
    if ($host !~* ^(mydomain.com|www.mydomain.com)$ ) {
        return 444;
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息:https://snakeycode.wordpress.com/2015/05/31/django-error-invalid-http_host-header/

博客文章引用了这个问题.

  • 这是我找到的最佳答案。谢谢。 (2认同)
  • 我仍然更喜欢您的答案,因为它在有问题的网站本身的文件中包含了解决方案,而不考虑其环境。例如,可以将其包含在模板中以用于设置新实例。 (2认同)

Lau*_*t S 9

我知道这是一个老问题,但这个问题就在今天发生在我身上。Django 文档上推荐的解决方案是在您的 nginx 配置中添加一个“捕获所有”nginx 服务器:

server {
    listen 80 default_server;
    return 444;
}
Run Code Online (Sandbox Code Playgroud)

官员nginx的文档建议相同的解决方案,或采取一些语法的细微差别。

这样,请求不会转到 django,当 nginx 收到格式错误的请求时,连接会立即关闭。

  • 这应该是公认的答案,特别是因为它引用了 Django 文档中的解决方案,并且比抑制电子邮件/日志记录更有意义。更新链接:https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/#environment-specific-settings (3认同)