web-dev-qa-db-fra.com

Comment désactiver l'erreur HTTP_Host invalide de Django?

Depuis que j'ai déployé un site utilisant Django 1.7 alpha (extrait de Git), je reçois parfois des messages d'erreur portant des titres tels que:

"En-tête HTTP_Host non valide: 'xxx.xxx.com'"

Je me rends compte que cela est dû au fait que l'en-tête HTTP Host: est défini sur un nom d'hôte ne figurant pas dans ALLOWED_HOSTS . Cependant, je ne contrôle pas quand et à quelle fréquence quelqu'un envoie une demande au serveur avec un nom d'hôte falsifié. Par conséquent, je n'ai pas besoin de plusieurs courriels d'erreur me laissant savoir que quelqu'un d'autre tente de faire quelque chose de louche.

Est-il possible de désactiver ce message d'erreur? Les paramètres de journalisation du projet se présentent comme suit:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'Django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'Django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'Django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}
41
Nathan Osman

Vous ne devriez pas ignorer cette erreur. Au lieu de cela, vous devriez refuser la demande avant qu’elle n’atteigne votre backend Django. Pour refuser des demandes sans ensemble Host, vous pouvez utiliser

SetEnvIfNoCase Host .+ VALID_Host
Order Deny,Allow
Deny from All
Allow from env=VALID_Host

ou forcer la correspondance avec un domaine particulier (exemple.com)

SetEnvIfNoCase Host example\.com VALID_Host
Order Deny,Allow
Deny from All
Allow from env=VALID_Host
52
Mark Lavin

Vous pouvez ajouter ceci à la section loggers de votre configuration de journalisation:

    'Django.security.DisallowedHost': {
        'handlers': ['mail_admins'],
        'level': 'CRITICAL',
        'propagate': False,
    },

Ceci définit le seuil de journalisation au-dessus du niveau ERROR utilisé par Django quand une SuspiciousOperation est détectée.

Alternativement, vous pouvez utiliser par exemple FileHandler pour consigner ces événements sans vous les envoyer par courrier électronique. Par exemple, pour utiliser un fichier dédié uniquement pour ces événements spécifiques, vous pouvez ajouter ceci à la section handlers:

    'spoof_logfile': {
        'level': 'ERROR',
        'class': 'logging.FileHandler',
        'filename': '/path/to/spoofed_requests.log',
    },

puis utilisez ceci dans la section loggers:

    'Django.security.DisallowedHost': {
        'handlers': ['spoof_logfile'],
        'level': 'ERROR',
        'propagate': False,
    },

Notez que la suggestion faite dans Django docs , d’utiliser

    'Django.security.DisallowedHost': {
        'handlers': ['null'],
        'propagate': False,
    },

dépend de votre exécution de Python 2.7 ou version ultérieure - sur 2.6, logging n'a pas NullHandler.

28
Vinay Sajip

Voici un exemple NGINX qui devrait empêcher votre Django de recevoir des demandes d’ordures.

server {
    listen 80 default_server;
    server_name _;
    return 418;
}


server {
    listen 80;
    # This will keep Django from receiving request with invalid Host
    server_name <SERVER_IP> your.domain.com;
    ...
9
Janusz Skonieczny

vous pouvez faire taire cette opération suspecte avec quelque chose comme

'loggers': {
    'Django.security.DisallowedHost': {
        'handlers': ['null'],
        'propagate': False,
   },

voir ceci pour plus de référence https://docs.djangoproject.com/en/dev/topics/logging/#Django-security

MODIFIER

vous devez également ajouter un gestionnaire 'null':

'handlers': {
    'null': {
        'level': 'DEBUG',
        'class': 'logging.NullHandler',
    },
}

vous n'avez probablement besoin que d'ajouter ceci et de modifier le niveau d'erreur (en remplaçant DEBUG par 'ERROR').

comme toujours, consultez la documentation pour connaître la syntaxe complète et la sémantique.

6
DRC

Avec Apache 2.4, il n’est pas nécessaire d’utiliser mod_setenvif. HTTP_Host est déjà une variable et peut être évalué directement:

WSGIScriptAlias / /path/to/wsgi.py

<Directory /path/to>
    <Files wsgi.py>
        Require expr %{HTTP_Host} == "example.com"
    </Files>
</Directory>
4
liquidki

Une autre façon de bloquer les demandes avec un en-tête d’hôte non valide avant d’atteindre Django consiste à utiliser une configuration default Apache avec un <VirtualHost> qui ne fait que renvoyer un 404. 

<VirtualHost *:80>
</VirtualHost>

Si vous définissez ceci comme votre premier hôte virtuel (par exemple, dans 000-default.conf) et que vous le suivez ensuite avec votre 'vrai' <VirtualHost>, complété par un <ServerName> et toutes les entrées <ServerAlias> à faire correspondre, Apache retournera un toute demande avec un en-tête Host qui ne correspond pas à <ServerName> ou à l'une de vos entrées <ServerAlias>. La clé permet de s'assurer que la valeur par défaut, 404 <VirtualHost>, est définie en premier, soit par nom de fichier ('000'), soit par la première entrée de votre fichier de configuration.

J'aime mieux cela que la solution populaire ci-dessus car elle est très explicite et facile à étendre.

3
Bob Barcklay

Les autres réponses sur cette page sont correctes si vous cherchez simplement à masquer ou à désactiver l’avertissement. Si vous autorisez intentionnellement chaque nom d'hôte, la valeur spéciale * peut être utilisée comme paramètre ALLOWED_HOSTS.

Pour empêcher entièrement la vérification du nom d’hôte, ajoutez la ligne suivante à votre settings.py:

ALLOWED_HOSTS = ['*']

Source: https://github.com/Django/django/blob/master/Django/http/request.py#L544-L563

def validate_Host(host, allowed_hosts):
    """
    Validate the given Host for this site.
    Check that the Host looks valid and matches a Host or Host pattern in the
    given list of ``allowed_hosts``. Any pattern beginning with a period
    matches a domain and all its subdomains (e.g. ``.example.com`` matches
    ``example.com`` and any subdomain), ``*`` matches anything, and anything
    else must match exactly.
    Note: This function assumes that the given Host is lower-cased and has
    already had the port, if any, stripped off.
    Return ``True`` for a valid Host, ``False`` otherwise.
    """
    for pattern in allowed_hosts:
        if pattern == '*' or is_same_domain(Host, pattern):
            return True

    return False
2
Wolph

Je ne peux pas encore commenter, mais puisque Order Deny, Allow est obsolète, vous pouvez le faire dans un hôte virtuel avec la directive Require actuelle:

<Directory /var/www/html/>
    SetEnvIfNoCase Host example\.com VALID_Host
    Require env VALID_Host
    Options
</Directory>
1
f71316

Dans setting.py set:

ALLOWED_HOSTS = ['yourweb.com']
0
Mu Sian Gong

pour plusieurs hôtes valides, vous pouvez:

SetEnvIfNoCase Host example\.com VALID_Host
SetEnvIfNoCase Host example2\.com VALID_Host
SetEnvIfNoCase Host example3\.com VALID_Host
Require env VALID_Host
0
ashier