Django 的 SuspiciousOperation 无效的 HTTP_HOST 标头
Posted
技术标签:
【中文标题】Django 的 SuspiciousOperation 无效的 HTTP_HOST 标头【英文标题】:Django's SuspiciousOperation Invalid HTTP_HOST header 【发布时间】:2013-02-20 17:19:48 【问题描述】:升级到 Django 1.5 后,我开始收到如下错误:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 92, in get_response
response = middleware_method(request)
File "/usr/local/lib/python2.7/dist-packages/django/middleware/common.py", line 57, in process_request
host = request.get_host()
File "/usr/local/lib/python2.7/dist-packages/django/http/request.py", line 72, in get_host
"Invalid HTTP_HOST header (you may need to set ALLOWED_HOSTS): %s" % host)
SuspiciousOperation: Invalid HTTP_HOST header (you may need to set ALLOWED_HOSTS): www.google.com
<WSGIRequest
path:/,
GET:<QueryDict: >,
POST:<QueryDict: >,
COOKIES:,
META:'CONTENT_LENGTH': '',
'CONTENT_TYPE': '',
'DOCUMENT_ROOT': '/etc/nginx/html',
'HTTP_ACCEPT': 'text/html',
'HTTP_HOST': 'www.google.com',
'HTTP_PROXY_CONNECTION': 'close',
'HTTP_USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)',
'PATH_INFO': u'/',
'QUERY_STRING': '',
'REMOTE_ADDR': '210.245.91.104',
'REMOTE_PORT': '49347',
'REQUEST_METHOD': 'GET',
'REQUEST_URI': '/',
u'SCRIPT_NAME': u'',
'SERVER_NAME': 'www.derekkwok.net',
'SERVER_PORT': '80',
'SERVER_PROTOCOL': 'HTTP/1.0',
'uwsgi.node': 'derekkwok',
'uwsgi.version': '1.4.4',
'wsgi.errors': <open file 'wsgi_errors', mode 'w' at 0xb6d99c28>,
'wsgi.file_wrapper': <built-in function uwsgi_sendfile>,
'wsgi.input': <uwsgi._Input object at 0x953e698>,
'wsgi.multiprocess': True,
'wsgi.multithread': False,
'wsgi.run_once': False,
'wsgi.url_scheme': 'http',
'wsgi.version': (1, 0)>
我在我的 settings.py 文件中设置了ALLOWED_HOSTS = ['.derekkwok.net']
。
这里发生了什么?有人冒充 Google 访问我的网站?还是有人错误地设置了 HTTP_HOST 标头的良性案例?
【问题讨论】:
你知道如何解决这个问题吗?面临同样的问题。每天记录大约一百个这样的错误。不知道这是否是我需要担心的事情。 这篇博文提供了一种停止电子邮件的好方法:tiwoc.de/blog/2013/03/… 备用答案***.com/a/25114003/1714030、***.com/a/21170400/1714030、***.com/q/15238506/1714030 和 ***.com/q/18220519/1714030 【参考方案1】:如果您使用 Nginx 将请求转发到在 Gunicorn/Apache/uWSGI 上运行的 Django,您可以使用以下命令来阻止错误请求。感谢@PaulM 的建议。
upstream app_server
server unix:/tmp/gunicorn_mydomain.com.sock fail_timeout=0;
server
...
## Deny illegal Host headers
if ($host !~* ^(mydomain.com|www.mydomain.com)$ )
return 444;
location /
proxy_pass http://app_server;
...
【讨论】:
很高兴看到这是对文档的改进hint hint :) @webjunkie,来自您的链接,“在某些情况下,您根本无法避免使用 if,例如,如果您需要测试没有等效指令的变量。”我的示例正确使用它并且在我的生产环境中运行良好。所以总而言之,一定要这样做! :) 您可以轻松避免它:只需指定您需要的 server_name,其余的由默认服务器处理程序处理。 查看此答案以获得类似的 Apache 配置:***.com/a/18792080 来自 webjunkie 提供的链接:“指令如果在位置上下文中使用时出现问题”。 Brent 给出的示例在server
块中使用if
,而不是在location
块中。这是否意味着在这种情况下if
可以?【参考方案2】:
当使用 Nginx 时,你可以设置你的服务器,只请求你想首先访问 Django 的主机。这应该不会再给您带来 SuspiciousOperation 错误了。
server
# default server
listen 80;
server_name _ default;
return 444;
server
# redirects
listen 80;
server_name example.com old.stuff.example.com;
return 301 http://www.example.com$request_uri;
server
# app
listen 80;
server_name www.example.com; # only hosts in ALLOWED_HOSTS here
location /
# ...
# ... your config/proxy stuff
【讨论】:
我喜欢这种方法而不是使用 Brent 建议的if
方法,但我无法让它与端口 443 一起使用。我尝试模仿你的建议(更改了监听端口),并且我的实际 SSL 站点没有加载——它被我添加的这个条目捕获。关于如何解决的任何想法?
ServerFault.com 上的另一位发帖人也有类似的问题,所以我按照他的建议,只针对 443 流量使用 if 语句方法
如果您也想捕获 SSL 请求,似乎您必须指定证书文件的路径(即使您只想丢弃):server listen 80 default_server; listen 443; server_name _; ssl_certificate /path/to/file.crt; ssl_certificate_key /path/to/file.key; return 444;
如果请求的HOST无效,Nginx会返回什么? 50 倍还是 40 倍?
这个配置有什么额外的?我在重定向和应用程序部分都设置了服务器名称,我仍然得到Invalid HTTP_HOST header
(使用 Django 1.8.x)【参考方案3】:
这已在较新版本的 Django 中得到修复,但如果您使用受影响的版本(例如 1.5),您可以向您的记录器处理程序添加过滤器以摆脱这些问题,如 this 博客文章中所述。
剧透:
from django.core.exceptions import SuspiciousOperation
def skip_suspicious_operations(record):
if record.exc_info:
exc_value = record.exc_info[1]
if isinstance(exc_value, SuspiciousOperation):
return False
return True
LOGGING =
'version': 1,
'disable_existing_loggers': False,
'filters':
'require_debug_false':
'()': 'django.utils.log.RequireDebugFalse',
,
# Define filter
'skip_suspicious_operations':
'()': 'django.utils.log.CallbackFilter',
'callback': skip_suspicious_operations,
,
,
'handlers':
'mail_admins':
'level': 'ERROR',
# Add filter to list of filters
'filters': ['require_debug_false', 'skip_suspicious_operations'],
'class': 'django.utils.log.AdminEmailHandler'
,
'loggers':
'django.request':
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
,
【讨论】:
实施的修复或版本的任何链接?谢谢 我在版本 2.0.5 上拥有它 这在较新版本的 Django 上不固定。我正在使用 Django 2.0.10【参考方案4】:如果您的ALLOWED_HOSTS
设置正确,则可能有人通过欺骗标头来探测您的网站是否存在漏洞。
Django 开发人员现在正在讨论将其从 500 内部服务器错误更改为 400 响应。见this ticket。
【讨论】:
我认为更可能的解释是网络爬虫(机器人)只是在端口 80 上爬取公共 IP 地址 - 在这种情况下,您会希望允许它们。 @markmnl 合法的网络爬虫不应该伪造主机头。 它只是使用 IP 地址而不是域名进行连接,并且 IP 地址不在 ALLOWED_HOSTS 中 - 或者至少这是发生在我身上的事情 - 我可以通过将浏览器指向它来复制它IP 地址。 是的。在任何半繁忙的站点中,这种情况每天都会发生。他们现在已经修复了它,但是这里有一个“插入式”应用程序,它可以在所有版本中对它进行分类,并带有一个错误率过滤器。 github.com/litchfield/django-safelogging 在互联网上部署我的网站后。我发现很多人试图使用无效主机访问我的网站。不仅使用IP地址。我想这可能是一些人试图找到一个无法防御 csrf 攻击的网站。以上是关于Django 的 SuspiciousOperation 无效的 HTTP_HOST 标头的主要内容,如果未能解决你的问题,请参考以下文章