Django ОШИБКА: неверный заголовок HTTP_HOST: u'/run/myprojectname/gunicorn.sock:'

Я знаю, что таких вопросов много на SO, но ни один из них не отвечает на мою конкретную проблему.

Я понимаю, что Джанго ALLOWED_HOSTS значение блокирует любые запросы к порту 80 на мой IP, которые не приходят с соответствующими Host: значение, и что когда приходит запрос, который не имеет правильного значения, 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.

Но этот вид меня бесит:

[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, я не понимаю, почему я получаю эти электронные письма вообще, так как этот билет был помечен как исправленный в течение некоторого времени.

Может кто-нибудь пролить свет на то, что мне не хватает?

Это мое 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

3 ответа

Решение

Похоже на

proxy_set_header Host $http_host

следует изменить на

proxy_set_header Host $host

а также server_name должен быть установлен соответственно на адрес, используемый для доступа к серверу. Если вы хотите, чтобы он все поймал, вы должны использовать server_name www.domainname.com "" ( документ здесь).

Я не уверен, но я думаю, что то, что вы видите, происходит, если клиент не отправляет Host: заголовок. Поскольку nginx не получает Host: заголовок, нет Host: Заголовок передается в Gunicorn. На данный момент, я думаю, что Gunicorn заполняет Host: как путь к сокету и говорит Django об этом, так как это соединение используется. С помощью $host и настройка server_name в Nginx должен обеспечить Host: правильно передан Gunicorn и исправить эту проблему.

Что касается электронной почты, то в соответствии с коммитом в тикете, который вы связали, похоже, что электронные письма по-прежнему отправляются запрещенным хостам. В документ также был добавлен способ отключения отправляемых писем:

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

Я сталкивался с некоторыми комментариями, которые предполагают, что подавление электронных писем не является хорошей идеей, потому что это непосредственно не решает проблему. Самое эффективное решение, которое я нашел, это добавить следующее в ваши настройки 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/

В блоге упоминается этот вопрос.

Я знаю, что это старый вопрос, но проблема произошла со мной только сегодня. Рекомендуемое решение для документации Django состоит в том, чтобы добавить сервер nginx "перехватить все" в вашей конфигурации nginx:

server {
    listen 80 default_server;
    return 444;
}

Официальные документы nginx рекомендуют то же решение, дают или принимают некоторые синтаксические нюансы.

Таким образом, запрос не переходит к django, соединение немедленно закрывается, когда nginx получает некорректный запрос.

Другие вопросы по тегам