SuspiciousOperation von Django Ungültiger HTTP_HOST-Header

95

Nach dem Upgrade auf Django 1.5 wurden folgende Fehler angezeigt:

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

Ich habe ALLOWED_HOSTS = ['.derekkwok.net'] in meiner settings.py-Datei festgelegt.

Was geht hier vor sich? Ist es jemand, der vorgibt, Google zu sein und auf meine Website zugreift? Oder ist es ein harmloser Fall, dass jemand seinen HTTP_HOST-Header falsch gesetzt hat?

Derek Kwok
quelle
Haben Sie herausgefunden, wie Sie das beheben können? Vor dem gleichen Problem. Jeden Tag werden ungefähr hundert dieser Fehler protokolliert. Keine Ahnung, ob ich mir darüber Sorgen machen muss.
Blinduck
3
Dieser Blog-Beitrag bietet eine gute
Derek Kwok

Antworten:

64

Wenn Ihr ALLOWED_HOSTSrichtig eingestellt ist, prüft möglicherweise jemand Ihre Site auf die Sicherheitsanfälligkeit, indem er den Header fälscht.

Derzeit diskutieren die Django-Entwickler, dies von einem internen 500-Server-Fehler in eine 400-Antwort zu ändern. Siehe dieses Ticket .

Brian Neal
quelle
1
Ich denke, eine wahrscheinlichere Erklärung ist, dass Webcrawler (Roboter) einfach öffentliche IP-Adressen auf Port 80 crawlen - in diesem Fall möchten Sie sie zulassen.
Markmnl
16
@markmnl Ein legitimer Webcrawler sollte keine Host-Header fälschen.
Brian Neal
1
Es wird nur eine Verbindung über die IP-Adresse hergestellt, nicht über den Domänennamen, und die IP-Adresse befindet sich nicht in ALLOWED_HOSTS - oder zumindest passierte dies bei mir - ich könnte es erneut anzeigen, indem ich meinen Browser auf die IP-Adresse zeige.
Markmnl
Ja. Und an jedem halb ausgelasteten Ort geschieht dies jeden Tag den ganzen Tag. Sie haben es jetzt behoben, aber hier ist eine "Drop-In" -App, die es in allen Versionen zusammen mit einem Fehlerratenfilter sortiert. github.com/litchfield/django-safelogging
s29
Nach der Bereitstellung meiner Website im Internet. Ich habe festgestellt, dass viele Leute versuchen, über einen ungültigen Host auf meine Website zuzugreifen. Nicht nur mit IP-Adresse. Ich denke, dies könnten einige Leute sein, die versuchen, eine Website zu finden, die einen CSRF-Angriff nicht verteidigen kann.
Ramwin
130

Wenn Sie Nginx verwenden, um Anfragen an Django weiterzuleiten, die unter Gunicorn / Apache / uWSGI ausgeführt werden, können Sie die folgenden Methoden verwenden, um fehlerhafte Anfragen zu blockieren. Vielen Dank an @PaulM für den Vorschlag und diesen Blog-Beitrag für ein Beispiel.

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

}
Brent O'Connor
quelle
7
Es wäre ausgezeichnet, dies als eine Verbesserung des Hinweises des Dokuments zu sehen :)
Paul McMillan
1
@webjunkie, Über Ihren Link: "Es gibt Fälle, in denen Sie die Verwendung eines if einfach nicht vermeiden können, beispielsweise wenn Sie eine Variable testen müssen, für die es keine entsprechende Anweisung gibt." Mein Beispiel verwendet es richtig und funktioniert gut in meiner Produktionsumgebung. Also abschließend, mach es so! :)
Brent O'Connor
2
Nun, Sie können es leicht vermeiden: Geben Sie einfach nur den Servernamen an, den Sie benötigen, und lassen Sie den Rest von einem Standard-Server-Handler erledigen.
Webjunkie
1
Siehe diese Antwort für eine ähnliche Apache-Konfiguration: stackoverflow.com/a/18792080
Denilson Sá Maia
1
Über den von webjunkie bereitgestellten Link: "Direktive, wenn Probleme bei der Verwendung im Standortkontext auftreten". Das von Brent gegebene Beispiel verwendet das ifInnere des serverBlocks und nicht den locationBlock. Bedeutet das, dass das ifin diesem Fall in Ordnung ist?
Brian Buck
31

Wenn Sie Nginx verwenden, können Sie Ihre Server so einrichten, dass nur Anfragen an die Hosts, die Sie erhalten möchten, an erster Stelle an Django gesendet werden. Das sollte Ihnen keine SuspiciousOperation-Fehler mehr geben.

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
}
Webjunkie
quelle
2
Ich mag diesen Ansatz gegenüber der Verwendung des ifvon Brent vorgeschlagenen Ansatzes, aber ich kann ihn nicht mit Port 443 zum Laufen bringen. Ich habe versucht, Ihren Vorschlag nachzuahmen (wobei der Listen-Port geändert wurde), und meine eigentliche SSL-Site wird nicht geladen - er wird von diesem Eintrag erfasst, den ich hinzugefügt habe. Irgendwelche Ideen, wie man das behebt?
Dolan Antenucci
1
Ein anderes Poster auf ServerFault.com hatte ähnliche Probleme, daher folgte ich seiner Empfehlung zum if-Anweisung-Ansatz nur für 443-Verkehr
Dolan Antenucci
1
Scheint, dass Sie den Pfad zu Zertifikatdateien angeben müssen, wenn Sie auch SSL-Anforderungen abfangen möchten (obwohl Sie nur verwerfen möchten): 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
Was gibt Nginx zurück, wenn der HOST der Anfrage ungültig ist? 50x oder 40x?
Laike9m
Was ist das Besondere an dieser Konfiguration? Ich habe den Servernamen sowohl in den Weiterleitungen als auch im App-Bereich festgelegt, ich bekomme immer noch Invalid HTTP_HOST header(mit Django 1.8.x)
Csaba Toth
16

Dies ist in neueren Versionen von Django behoben. Wenn Sie jedoch eine betroffene Version (z. B. 1.5) verwenden, können Sie Ihrem Logger-Handler einen Filter hinzufügen, um diese zu entfernen, wie in diesem Blogbeitrag beschrieben.

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,
        },
    }
}
mgalgs
quelle
1
Gibt es einen Link für das Update oder die Version, wo implementiert? Thx
Marc
1
Ich hatte es auf Version 2.0.5
Mehmet
Dies ist bei neueren Versionen von Django nicht behoben. Ich benutze Django 2.0.10
javidazac