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

Posted

技术标签:

【中文标题】Django 错误:无效的 HTTP_HOST 标头:u\'/run/myprojectname/gunicorn.sock:\'【英文标题】:Django ERROR: Invalid HTTP_HOST header: u'/run/myprojectname/gunicorn.sock:'Django 错误:无效的 HTTP_HOST 标头:u'/run/myprojectname/gunicorn.sock:' 【发布时间】:2014-10-11 19:30:35 【问题描述】:

我知道在 SO 上有很多这样的问题,但似乎没有一个能回答我的特定问题。

我了解 Django 的 ALLOWED_HOSTS 值阻止了任何对我 IP 上的端口 80 的请求,这些请求没有提供适当的 Host: 值,并且当请求进入时,它没有正确的值,Django 正在给我发一封电子邮件。我也知道 slick nginx hack 可以解决此问题,但我正在尝试了解此类请求的性质并确定这是否是我需要担心的安全问题。

这样的请求是有意义的:

[Django] ERROR: Invalid HTTP_HOST header: '203.0.113.1'.  You may need to add u'203.0.113.1' to ALLOWED_HOSTS.

但这一种让我感到害怕:

[Django] ERROR: Invalid HTTP_HOST header: u'/run/my_project_name/gunicorn.sock:'.

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

此外,由于我正在运行 Django 1.6.5,我完全不明白为什么我会收到这些电子邮件,因为 this ticket 已被标记为已修复一段时间了。

有人能解释一下我错过了什么吗?

这是我的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

这是我的 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;
    
  

最后,我在我的 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:/"

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

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

【问题讨论】:

【参考方案1】:

好像

proxy_set_header Host $http_host

should be changed到

proxy_set_header Host $host

server_name should be set appropriately 到用于访问服务器的地址。如果你想让它全部捕获,你应该使用server_name www.domainname.com "" (doc here)。

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

关于电子邮件,根据您链接的票证中的commit,看起来仍在为不允许的主机发送电子邮件。文档中还添加了suggested a way to disable the emails being sent:

    'loggers': 
        'django.security.DisallowedHost': 
        'handlers': ['null'],
        'propagate': False,
    ,

【讨论】:

这听起来很合理,但我想测试这样的请求,看看我是否可以重现它。运行 curl 203.0.113.1 当前会导致一封电子邮件,声称 203.0.113.1 是无效的主机标头,curl 203.0.113.1 -H 'Host:' 导致根本没有邮件。你能解释一下我如何重现给我那个 gunicorn 电子邮件的请求吗? 对于问题的第二部分,为什么这些电子邮件会通过?如果 ALLOWED_HOSTS 已经拒绝它们,为什么 Django 会向我发送有关它的电子邮件? 我设法通过使用 telnet 和发送 HEAD / HTTP/1.0 重新创建了 gunicorn 电子邮件。所以我不再担心我的配置泄漏的东西。然而,即使在将server_name 设置为myproject.mydomain.tld 并设置proxy_set_header Host $host 之后,电子邮件仍然会不断涌入:-( 我已经更新了 nginx 配置以显示新值。 @DanielQuinn 是的,很确定它没有泄漏外部的套接字路径......这是在内部某个地方传递的东西。所以你还看到像[Django] ERROR: Invalid HTTP_HOST header: u'/run/my_project_name/gunicorn.sock:'.这样的东西吗?我原以为根据上述更新设置后它不会再显示该错误。此外,更新了有关如何阻止针对此错误发送电子邮件的答案。 感谢 Django sn-p。我不知道我需要明确禁止此类消息。你是对的,gunicorn 电子邮件已经停止进来,尽管我知道原因:现在向我的 ip 发出 HEAD 请求 / 只是返回我网站的首页头数据。你会认为 ALLOWED_HOSTS 也会拒绝对不允许主机的 HEAD 请求。【参考方案2】:

我遇到了一些 cmets,他们认为隐藏电子邮件不是一个好主意,因为它不能直接解决问题。我发现最有效的解决方案是将以下内容添加到您的 nginx 设置中:

server 

    ...

    ## Deny illegal Host headers
    if ($host !~* ^(mydomain.com|www.mydomain.com)$ ) 
        return 444;
    

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

博文引用了这个问题。

【讨论】:

这是我找到的最佳答案。谢谢。 @Teekin 我建议你看看这个答案***.com/a/44118369/785808,因为它来自官方文档。 我还是更喜欢你的回答,因为它包含了问题网站本身的文件中的解决方案,而不考虑它的环境。例如,它可以包含在用于设置新实例的模板中。 有人潜入我们的服务器,这个解决方案在阻止带有错误标头的不需要的传入请求方面非常有效。【参考方案3】:

我知道这是一个老问题,但这个问题今天才发生在我身上。 Django docs 上推荐的解决方案是在你的 nginx 配置中添加一个“catch all” nginx 服务器:

server 
    listen 80 default_server;
    return 444;

official nginx docs 推荐相同的解决方案,给出或接受一些语法细微差别。

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

【讨论】:

这应该是公认的答案,尤其是因为它引用了 Django 文档中的解决方案,并且比抑制电子邮件/日志记录更有意义。更新链接:docs.djangoproject.com/en/2.1/howto/deployment/checklist/… 我的 nginx 配置中有来自 Ernest Jumbe's answer 的“拒绝非法主机标头”解决方案,但仍然收到来自 gunicorn 的错误。这个答案永久修复了它。用this.测试它

以上是关于Django 错误:无效的 HTTP_HOST 标头:u'/run/myprojectname/gunicorn.sock:'的主要内容,如果未能解决你的问题,请参考以下文章

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

将 django 站点从 http 升级到 https 后,我不断收到“无效的 HTTP_HOST 标头”错误电子邮件

Django 的 SuspiciousOperation 无效的 HTTP_HOST 标头

错误:无效的 HTTP_HOST 标头:'/webapps/../gunicorn.sock'

Django 无效的 http_host

避免使用 Django + Elastic Beanstalk 获得“无效的 HTTP_HOST 标头:'localhost'”消息