67

自从我部署了一个运行 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,
        },
    }
}
4

13 回答 13

63

你不应该忽略这个错误。相反,您应该在请求到达您的 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
于 2013-09-13T17:33:19.307 回答
40

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

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

这会将日志记录阈值设置为高于ERRORDjango 在SuspiciousOperation检测到 a 时使用的级别。

或者,您可以使用例如 aFileHandler来记录这些事件,而无需通过电子邮件发送给您。例如,要为这些特定事件使用专用文件,您可以将其添加到该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 文档中提出的建议,使用

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

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

于 2013-09-13T16:50:49.413 回答
9

这是 NGINX 示例,它应该可以防止您的 django 接收垃圾请求。

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    return 444;
}


server {
    listen 80;
    # This will keep Django from receiving request with invalid host
    server_name <SERVER_IP> your.domain.com;
    ...
于 2015-02-27T11:04:28.980 回答
8

您可以使用类似的东西使特定的 SuspiciousOperation 静音

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

有关更多参考,请参见https://docs.djangoproject.com/en/dev/topics/logging/#django-security

编辑

您还需要添加一个“空”处理程序:

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

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

与往常一样,请参阅文档以获取完整的语法和语义。

于 2013-08-13T22:55:18.763 回答
8

使用 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>
于 2017-04-10T12:24:18.063 回答
5

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

<VirtualHost *:80>
</VirtualHost>

如果您将其定义为您的第一个虚拟主机(例如在 000-default.conf 中),然后在它后面加上您的 'real' <VirtualHost>,并加上您想要匹配的 a<ServerName>和任何 <ServerAlias>条目,Apache 将为任何请求返回 404Host不匹配的标题<ServerName>或您的<ServerAlias>条目之一。确保<VirtualHost>首先定义默认值 404 的关键,通过文件名('000')或配置文件中的第一个条目。

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

于 2015-05-12T00:07:22.483 回答
4

django 文档专门解决了这个问题。他们建议将其放入您的日志记录设置中

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

此外,如果您使用的是 Sentry,则需要添加以下内容以防止 Sentry 拾取它:

from sentry_sdk.integrations.logging import ignore_logger
ignore_logger("django.security.DisallowedHost")
于 2020-09-10T19:58:19.937 回答
4

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

注意:这可能会引入安全漏洞。

在某些情况下,Django 使用客户端提供的 Host 标头来构造 URL。虽然对这些值进行了清理以防止跨站点脚本攻击,但假主机值可用于跨站点请求伪造、缓存中毒攻击和电子邮件中的中毒链接。

因为即使看似安全的 Web 服务器配置也容易受到虚假 Host 标头的影响,Django 会根据 django.http.HttpRequest.get_host() 方法中的 ALLOWED_HOSTS 设置验证 Host 标头。

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

ALLOWED_HOSTS = ['*']

来源:https ://github.com/django/django/blob/33c365781abbcc1b21a31b31d95d344a174df0d5/django/http/request.py#L653-L668

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 lowercased and has
    already had the port, if any, stripped off.

    Return ``True`` for a valid host, ``False`` otherwise.
    """
    return any(pattern == '*' or is_same_domain(host, pattern) for pattern in allowed_hosts)
于 2017-01-28T14:40:59.907 回答
4

我还不能发表评论,但由于 Order Deny, Allow 已被弃用,使用当前 Require 指令在虚拟主机中执行此操作的方法是:

<Directory /var/www/html/>
    SetEnvIfNoCase Host example\.com VALID_HOST
    Require env VALID_HOST
    Options
</Directory>
于 2016-10-04T22:17:29.220 回答
1

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

SetEnvIfNoCase Host example\.com VALID_HOST
SetEnvIfNoCase Host example2\.com VALID_HOST
SetEnvIfNoCase Host example3\.com VALID_HOST
Require env VALID_HOST
于 2017-05-01T11:40:09.993 回答
0

还要通过 Apache 处理以下错误:

  • 无效的 HTTP_HOST 标头:“ _my .domain.com ”。根据RFC 1034/1035,提供的域名无效。

我们可以使用正则表达式, ^[^_]+将匹配包含 1 个或多个字符的字符串,该字符串包含子域中除下划线以外的任何字符,如下例所示。

我们可以将它应用到wsgi.py文件中

<VirtualHost xxx.xxx.xxx.xxx:XX>
    ...

    SetEnvIfNoCase Host "^[^_]+\.my-domain\.com" VALID_HOST
    <Files wsgi.py>
        <RequireAll>
            Require all granted
            Require env VALID_HOST
        </RequireAll>
    </Files>
    
    ...
</VirtualHost>

使用Require expr

<VirtualHost xxx.xxx.xxx.xxx:XX>
    ...


    <Files wsgi.py>

        Require expr %{HTTP_HOST} =~ m#^[^_]+\.my-domain\.com#

    </Files>


    ...

</VirtualHost>

或者我们可以使用<Location "/">,这是一种将配置应用于整个服务器的简单方法。

<VirtualHost xxx.xxx.xxx.xxx:XX>
    ...

    SetEnvIfNoCase Host "^[^_]+\.my-domain\.com" VALID_HOST
    <Location />
        <RequireAll>
            Require all granted
            Require env VALID_HOST
        </RequireAll>
    </Location>
    
    ...
</VirtualHost>

来自 Apache 文档:

何时使用<Location "/">

使用 <Location> 将指令应用于文件系统之外的内容。对于存在于文件系统中的内容,使用和 . <Location "/"> 是一个例外这是一种 将配置应用于整个服务器的简单方法。

答案基于Apache 模块 mod_setenvif以及如何阻止来自特定机器人的持久请求

于 2022-01-10T12:31:11.780 回答
0

在 setting.py 中设置:

ALLOWED_HOSTS = ['yourweb.com']
于 2016-11-29T13:17:30.707 回答
0

这是防止您的 django 接收此类请求所需的 NGINX 块。

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    listen 443 ssl default_server;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    return 444;
}
于 2021-09-24T21:14:40.743 回答