Tiêu đề HTTP_HOST không hợp lệ của Django


95

Sau khi nâng cấp lên Django 1.5, tôi bắt đầu gặp lỗi như sau:

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

Tôi đã đặt ALLOWED_HOSTS = ['.derekkwok.net'] trong tệp settings.py của mình.

Chuyện gì đang xảy ra ở đây? Ai đó giả danh Google và truy cập trang web của tôi? Hoặc đó là một trường hợp lành tính của ai đó đặt tiêu đề HTTP_HOST của họ không chính xác?


Bạn đã tìm ra cách khắc phục điều này chưa? Đối mặt với cùng một vấn đề. Ghi lại khoảng một trăm lỗi này mỗi ngày. Không biết đó có phải là điều tôi cần lo lắng hay không.
blinduck

3
Bài đăng trên blog này cung cấp một cách hay để ngăn chặn các email: tiwoc.de/blog/2013/03/…
Derek Kwok

Câu trả lời:


64

Nếu của bạn ALLOWED_HOSTSđược đặt chính xác, thì có thể ai đó đang thăm dò trang web của bạn để tìm lỗ hổng bằng cách giả mạo tiêu đề.

Hiện đang có cuộc thảo luận của các nhà phát triển Django để thay đổi điều này từ lỗi máy chủ nội bộ 500 thành phản hồi 400. Xem vé này .


1
Tôi nghĩ rằng một lời giải thích có khả năng hơn là trình thu thập dữ liệu web (rô bốt) chỉ đơn giản là thu thập các địa chỉ IP công cộng trên cổng 80 - trong trường hợp đó bạn muốn cho phép chúng.
markmnl,

16
@markmnl Một trình thu thập thông tin web hợp pháp không được giả mạo tiêu đề máy chủ.
Brian Neal

1
Nó chỉ đang kết nối bằng địa chỉ IP không phải tên miền và địa chỉ IP không nằm trong ALLOWED_HOSTS - hoặc ít nhất đó là những gì đang xảy ra với tôi - tôi có thể thực hiện lại nó bằng cách trỏ trình duyệt của mình đến địa chỉ IP.
markmnl

Vâng. Và trong bất kỳ trang web bận rộn nào, điều này xảy ra cả ngày mỗi ngày. Họ đã sửa lỗi ngay bây giờ, nhưng đây là một ứng dụng "thả vào" sắp xếp nó trên tất cả các phiên bản cùng với bộ lọc tỷ lệ lỗi. github.com/litchfield/django-safelogging
s29

Sau khi triển khai trang web của tôi trên internet. Tôi thấy rất nhiều người đang cố truy cập vào trang web của tôi bằng cách sử dụng máy chủ lưu trữ không hợp lệ. Không chỉ sử dụng địa chỉ IP. Tôi nghĩ rằng đây có thể là một số người đang cố gắng tìm một trang web không thể chống lại cuộc tấn công csrf.
ramwin

130

Nếu bạn đang sử dụng Nginx để chuyển tiếp các yêu cầu tới Django đang chạy trên Gunicorn / Apache / uWSGI, bạn có thể sử dụng cách sau để chặn các yêu cầu xấu. Cảm ơn @PaulM về đề xuất và bài đăng trên blog này là một ví dụ.

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

}

7
Nó sẽ là tuyệt vời để xem đây là một sự cải tiến để các tài liệu gợi ý gợi ý :)
Paul McMillan

1
@webjunkie, Từ liên kết của bạn, "Có những trường hợp bạn không thể tránh sử dụng if, ví dụ: nếu bạn cần kiểm tra một biến không có chỉ thị tương đương." Ví dụ của tôi sử dụng nó một cách chính xác và hoạt động tốt trong môi trường sản xuất của tôi. Vì vậy, kết luận, hãy làm như thế này! :)
Brent O'Connor vào

2
Bạn có thể dễ dàng tránh nó: Chỉ cần chỉ định server_name bạn cần và để phần còn lại được xử lý bởi trình xử lý máy chủ mặc định.
webjunkie

1
Xem câu trả lời này để biết cấu hình Apache tương tự: stackoverflow.com/a/18792080
Denilson Sá Maia

1
Từ liên kết được cung cấp bởi webjunkie: "Chỉ thị nếu có vấn đề khi sử dụng trong ngữ cảnh vị trí". Ví dụ được đưa ra bởi Brent sử dụng ifbên trong serverkhối chứ không phải trong locationkhối. Điều đó có nghĩa iflà ổn trong trường hợp này?
brian buck

31

Khi sử dụng Nginx, bạn có thể thiết lập các máy chủ của mình theo cách chỉ yêu cầu các máy chủ mà bạn muốn truy cập Django ngay từ đầu. Điều đó sẽ không cho bạn lỗi SuspiciousOperation nữa.

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
}

2
Tôi thích cách tiếp cận này hơn là sử dụng cách iftiếp cận do Brent đề xuất, nhưng tôi không thể làm cho nó hoạt động với cổng 443. Tôi đã thử bắt chước đề xuất của bạn (với cổng lắng nghe đã thay đổi) và trang web SSL thực tế của tôi không tải - nó được nắm bắt bởi mục nhập này tôi đã thêm. Có cách nào để sửa không?
Dolan Antenucci,

1
Một tấm áp phích trên ServerFault.com có vấn đề tương tự, vì vậy tôi đi theo đề nghị của ông về cách tiếp cận nếu-tuyên bố cho 443 giao thông chỉ
Dolan Antenucci

1
Có vẻ như bạn phải chỉ định đường dẫn đến tệp chứng chỉ nếu bạn cũng muốn bắt các yêu cầu SSL (mặc dù bạn chỉ muốn loại bỏ): server { listen 80 default_server; listen 443; server_name _; ssl_certificate /path/to/file.crt; ssl_certificate_key /path/to/file.key; return 444; }
n__o 29/12/14

Nginx sẽ trả lại gì nếu HOST của yêu cầu không hợp lệ? 50x hay 40x?
laike9m

Phần bổ sung trong cấu hình này là gì? Tôi đã đặt tên máy chủ cả trong chuyển hướng và phần ứng dụng, tôi vẫn nhận được Invalid HTTP_HOST header(với Django 1.8.x)
Csaba Toth

16

Điều này đã được khắc phục trong các phiên bản Django mới hơn, nhưng nếu bạn đang sử dụng phiên bản bị ảnh hưởng (ví dụ: 1.5), bạn có thể thêm bộ lọc vào trình xử lý trình ghi nhật ký của mình để loại bỏ chúng, như được nêu trong bài đăng blog này .

Spoiler:

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

1
Bất kỳ liên kết nào cho bản sửa lỗi hoặc phiên bản được triển khai? Thx
Marc

1
Tôi đã có nó trên phiên bản 2.0.5
mehmet

Điều này không được khắc phục trên các phiên bản Django mới hơn. Tôi đang sử dụng Django 2.0.10
javidazac
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.