如何禁用Django的无效HTTP_HOST错误?

时间:2013-08-13 22:47:56

标签: django logging http-host

自从我部署了运行Django 1.7 alpha(从Git检出)的网站以来,我偶尔会收到错误消息,标题如下:

  

“HTTP_HOST标头无效:'xxx.xxx.com'”

我意识到这是由于Host: HTTP标头设置为ALLOWED_HOSTS中未列出的主机名。但是,我无法控制某人使用伪造主机名向服务器发送请求的时间和频率。因此,我不需要一堆错误电子邮件让我知道其他人正试图做一些可疑的事情。

有没有办法禁用此错误消息?项目的日志记录设置如下所示:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

11 个答案:

答案 0 :(得分:52)

你不应该忽略这个错误。相反,你应该在它到达你的Django后端之前拒绝请求。要拒绝未设置HOST的请求,您可以使用

SetEnvIfNoCase Host .+ VALID_HOST
Order Deny,Allow
Deny from All
Allow from env=VALID_HOST

或强制将匹配项移至特定域(example.com)

SetEnvIfNoCase Host example\.com VALID_HOST
Order Deny,Allow
Deny from All
Allow from env=VALID_HOST

答案 1 :(得分:29)

您可以将其添加到日志配置的loggers部分:

    'django.security.DisallowedHost': {
        'handlers': ['mail_admins'],
        'level': 'CRITICAL',
        'propagate': False,
    },

这会将日志记录阈值设置为Django在检测到ERROR时使用的SuspiciousOperation级别以上。

或者,您可以使用例如一个FileHandler来记录这些事件而不通过电子邮件发送给您。例如,要仅为这些特定事件使用专用文件,您可以将其添加到handlers部分:

    'spoof_logfile': {
        'level': 'ERROR',
        'class': 'logging.FileHandler',
        'filename': '/path/to/spoofed_requests.log',
    },

然后在loggers部分使用此内容:

    'django.security.DisallowedHost': {
        'handlers': ['spoof_logfile'],
        'level': 'ERROR',
        'propagate': False,
    },

请注意Django docs中的建议,使用

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

取决于您运行Python 2.7或更高版本 - 在2.6上,logging没有NullHandler

答案 2 :(得分:8)

这是NGINX示例,应该阻止你的django收到垃圾请求。

server {
    listen 80 default_server;
    server_name _;
    return 418;
}


server {
    listen 80;
    # This will keep Django from receiving request with invalid host
    server_name <SERVER_IP> your.domain.com;
    ...

答案 3 :(得分:6)

你可以用类似

之类的东西来沉默那个特定的SuspiciousOperation
'loggers': {
    'django.security.DisallowedHost': {
        'handlers': ['null'],
        'propagate': False,
   },

请参阅此内容以获取更多参考资料https://docs.djangoproject.com/en/dev/topics/logging/#django-security

修改

你还需要添加一个'null'处理程序:

'handlers': {
    'null': {
        'level': 'DEBUG',
        'class': 'logging.NullHandler',
    },
}

可能你只需要添加它并修改错误级别(用'ERROR'替换DEBUG)。

总是在documentation中引用完整的语法和语义。

答案 4 :(得分:4)

在到达Django之前使用无效主机标头阻止请求的另一种方法是使用默认 Apache配置,<VirtualHost>除了返回404之外什么都不做。

<VirtualHost *:80>
</VirtualHost>

如果您将其定义为第一个虚拟主机(例如在000-default.conf中),然后将其与“真实”<VirtualHost>一起使用,请填写<ServerName>和任何&lt; {{ 1}}您要匹配的条目,对于ServerAlias>标头与Host或您的<ServerName>条目之一不匹配的任何请求,Apache将返回404。确保首先定义默认值404 <ServerAlias>的关键,可以通过文件名('000')或配置文件中的第一个条目来定义。

我比上面流行的解决方案更喜欢这个,因为它非常明确且易于扩展。

答案 5 :(得分:4)

使用Apache 2.4,不需要使用mod_setenvif。 HTTP_HOST已经是一个变量,可以直接评估:

WSGIScriptAlias / /path/to/wsgi.py

<Directory /path/to>
    <Files wsgi.py>
        Require expr %{HTTP_HOST} == "example.com"
    </Files>
</Directory>

答案 6 :(得分:1)

我还没有发表评论,但是由于拒绝订单,不赞成允许,在具有当前Require指令的虚拟主机中执行此操作的方法是:

Unbound variable: below-80

答案 7 :(得分:1)

如果您只是想隐藏或禁用警告,此页面上的其他答案都是正确的。如果您有意允许每个主机名,则*的特殊值可用作ALLOWED_HOSTS设置。

要完全阻止主机名检查,请将以下行添加到settings.py

ALLOWED_HOSTS = ['*']

来源:https://github.com/django/django/blob/master/django/http/request.py#L544-L563

def validate_host(host, allowed_hosts):
    """
    Validate the given host for this site.
    Check that the host looks valid and matches a host or host pattern in the
    given list of ``allowed_hosts``. Any pattern beginning with a period
    matches a domain and all its subdomains (e.g. ``.example.com`` matches
    ``example.com`` and any subdomain), ``*`` matches anything, and anything
    else must match exactly.
    Note: This function assumes that the given host is lower-cased and has
    already had the port, if any, stripped off.
    Return ``True`` for a valid host, ``False`` otherwise.
    """
    for pattern in allowed_hosts:
        if pattern == '*' or is_same_domain(host, pattern):
            return True

    return False

答案 8 :(得分:0)

在setting.py中设置:

ALLOWED_HOSTS = ['yourweb.com']

答案 9 :(得分:0)

对于多个有效主机,您可以:

SetEnvIfNoCase Host example\.com VALID_HOST
SetEnvIfNoCase Host example2\.com VALID_HOST
SetEnvIfNoCase Host example3\.com VALID_HOST
Require env VALID_HOST

答案 10 :(得分:0)

django docs专门针对此地址。他们建议将其放入您的日志记录设置

LOGGING = {
    "handlers": {
        # ...
        "null": {
            "class": "logging.NullHandler",
        },
    },
    "loggers": {
        # ...
        "django.security.DisallowedHost": {
            "handlers": ["null"],
            "propagate": False,
        },
    },
}