Django的SuspiciousOperation HTTP_HOST头无效

升级到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头的良性情况?

如果您的ALLOWED_HOSTS设置正确,则可能是有人通过欺骗标头来检测您的站点是否存在漏洞。

Django开发者现在正在讨论将这个从500内部服务器错误改为400响应。 看到这张票 。

如果您使用Nginx将请求转发到在Gunicorn / Apache / uWSGI上运行的Django,则可以使用以下命令来阻止错误的请求。 感谢@PaulM的build议和这个博客文章的例子。

 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; ... } } 

在使用Nginx的时候,你可以设置你的服务器,只要求你首先到达Django的主机。 这应该不会给你可疑的操作错误了。

 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 } 

在Django的新版本中已经修复了这个问题,但是如果你使用的是受影响的版本(例如1.5),你可以在你的logging器处理程序中添加一个filter来消除这些,正如本博文所述。

扰stream板:

 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, }, } }