106 votes

SuspiciousOperation de Django En-tête HTTP_HOST invalide

Après la mise à niveau vers Django 1.5, j'ai commencé à obtenir des erreurs comme celle-ci :

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

J'ai mis ALLOWED_HOSTS = ['.derekkwok.net'] dans mon fichier settings.py.

Qu'est-ce qui se passe ici ? Quelqu'un se fait-il passer pour Google et accède-t-il à mon site ? Ou s'agit-il d'un cas bénin où quelqu'un a mal défini son en-tête HTTP_HOST ?

0 votes

Avez-vous trouvé le moyen de résoudre ce problème ? Je suis confronté au même problème. J'enregistre une centaine de ces erreurs chaque jour. Aucune idée si c'est quelque chose dont je dois m'inquiéter.

3 votes

Cet article de blog propose une bonne façon d'arrêter les courriels : tiwoc.de/blog/2013/03/

154voto

Brent Points 977

Si vous utilisez Nginx pour transmettre des requêtes à Django qui s'exécute sur Gunicorn/Apache/uWSGI, vous pouvez utiliser les éléments suivants pour bloquer les mauvaises requêtes. Merci à @PaulM pour la suggestion.

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

}

8 votes

Il serait excellent de voir cela comme une amélioration de la documentation. indice indice indice :)

0 votes

Pour une raison quelconque, cela n'a pas fonctionné pour moi... Cependant, @tiwoc a proposé une solution de contournement au niveau de Django qui a fonctionné à merveille. Voir ma réponse .

0 votes

Oui, je vous crois :). Cependant, je préfère personnellement la solution django car elle vit avec mon projet et offre plus de flexibilité si je le souhaite vraiment.

66voto

Brian Neal Points 13668

Si votre ALLOWED_HOSTS est correctement configuré, il est possible que quelqu'un recherche la vulnérabilité sur votre site en usurpant l'en-tête.

Les développeurs de Django discutent actuellement de la possibilité de remplacer l'erreur 500 du serveur interne par une réponse 400. Voir ce billet .

1 votes

Je pense qu'une explication plus probable est que les crawlers web (robots) explorent simplement les adresses IP publiques sur le port 80 - dans ce cas, vous devriez les autoriser.

18 votes

@markmnl Un robot d'exploration légitime ne devrait pas falsifier les en-têtes d'hôtes.

1 votes

Il se connecte simplement en utilisant l'adresse IP et non le nom de domaine, et l'adresse IP n'est pas dans les ALLOWED_HOSTS - ou du moins c'est ce qui se passait avec moi - je pouvais le reprocher en faisant pointer mon navigateur vers l'adresse IP.

31voto

webjunkie Points 2101

Si vous utilisez Nginx, vous pouvez configurer vos serveurs de manière à ce que seules les demandes adressées aux hôtes souhaités parviennent à Django. Vous ne devriez plus avoir d'erreurs 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
}

2 votes

J'aime cette approche plutôt que d'utiliser le if suggérée par Brent, mais je n'arrive pas à la faire fonctionner avec le port 443. J'ai essayé d'imiter votre suggestion (en modifiant le port d'écoute), mais mon site SSL actuel ne se charge pas - il est capturé par cette entrée que j'ai ajoutée. Avez-vous une idée de la façon de résoudre le problème ?

1 votes

Une autre affiche sur ServerFault.com J'ai eu des problèmes similaires, j'ai donc suivi sa recommandation sur l'approche if-statement pour le trafic 443 uniquement.

2 votes

Il semble que vous deviez spécifier le chemin d'accès aux fichiers de certificat si vous souhaitez également capturer les demandes SSL (même si vous souhaitez simplement les rejeter) : server { listen 80 default_server; listen 443; server_name _; ssl_certificate /path/to/file.crt; ssl_certificate_key /path/to/file.key; return 444; }

16voto

mgalgs Points 2203

Ce problème est corrigé dans les versions plus récentes de Django, mais si vous utilisez une version affectée (par exemple la 1.5), vous pouvez ajouter un filtre à votre gestionnaire de journaux pour vous en débarrasser, comme indiqué dans le document suivant este blog post.

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 votes

Un lien vers le correctif ou la version où il a été implémenté ? Thx

1 votes

Je l'avais sur la version 2.0.5

1 votes

Ce problème n'est pas corrigé sur les versions plus récentes de Django. J'utilise Django 2.0.10.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X