La sécurité dans Django

Ce document est un aperçu des fonctionnalités de sécurité dans Django. Il contient des conseils sur la sécurisation des sites basés sur Django.

Protection contre le « Cross site scripting » (XSS)

Les attaques XSS permettent à un intrus d’injecter des scripts clients dans les navigateurs des utilisateurs. Le principe général est de stocker les scripts malveillants dans la base de données d’où ils seront repris et affichés pour d’autres utilisateurs, ou encore d’amener les utilisateurs à cliquer sur un lien qui va provoquer l’exécution du JavaScript de l’attaquant dans le navigateur des utilisateurs. Cependant, les attaques XSS peuvent provenir de n’importe quelle source de données non fiable, comme les cookies ou les services Web, à chaque fois que les données ne sont pas suffisamment nettoyées avant d’être incluses dans une page.

L’utilisation des gabarits Django vous protège de la majorité des attaques XSS. Cependant, il est important de comprendre les protections appliquées et leurs limites.

Les gabarits de Django échappent des caractères spécifiques qui sont particulièrement dangereux en HTML. Bien que cela protège les utilisateurs de la plupart des saisies malveillantes, cela ne constitue pas une protection absolue. Par exemple, cela ne protège pas contre ceci :

<style class={{ var }}>...</style>

Si var contient 'class1 onmouseover=javascript:func()', cela peut amener à une exécution de JavaScript non autorisée, selon la manière dont le navigateur produit le HTML imparfait (l’ajout de guillemets autour de cette valeur d’attribut réglerait ce cas).

Il est aussi important d’être particulièrement prudent lors de l’utilisation de is_safe avec des balises de gabarit personnalisées, avec la balise de gabarit safe, avec mark_safe et quand l’échappement automatique est désactivé.

De plus, si vous utilisez le système des gabarits pour produire du contenu autre que du HTML, les caractères et les mots nécessitant l’échappement peuvent être totalement différents.

Vous devez aussi être très prudent lorsque vous stockez du code HTML dans la base de données, en particulier quand ce contenu est sélectionné et affiché.

Protection contre le « Cross site request forgery » (CSRF)

Les attaques CSRF permettent à une personne malveillante d’exécuter des actions en utilisant les données d’authentification d’un autre utilisateur sans que ce dernier ne s’en rende compte.

Django offre une protection intégrée contre la plupart des types d’attaques CSRF, pour autant que vous l’ayez activée et que vous l’utilisiez de manière appropriée. Toutefois, comme pour toute technique de protection, elle est limitée. Par exemple, il est possible de désactiver le module CSRF de manière globale ou pour certaines vues. Vous ne devriez le faire que si vous savez ce que vous faites. Il existe d’autres limites si votre site contient des sous-domaines qui ne sont pas sous votre contrôle.

La protection CSRF fonctionne en contrôlant un jeton dans chaque requête POST. Cela garantit qu’un utilisateur malveillant ne peut simplement « rejouer » un envoi de formulaire POST sur votre site Web tout en faisant soumettre ce formulaire de manière involontaire par un autre utilisateur connecté. L’utilisateur malveillant devrait connaître le jeton qui est spécifique à l’utilisateur (en utilisant un cookie).

Lorsqu’il est déployé avec HTTPS, CsrfViewMiddleware vérifie que l’en-tête « HTTP referer » contient une URL de même origine (y compris le sous-domaine et le port). Comme HTTPS offre une sécurité supplémentaire, il est impératif de s’assurer que les connexions utilisent HTTPS quand c’est possible en redirigeant les requêtes de connexion non sécurisées et en utilisant HSTS pour les navigateurs qui le prennent en charge.

Soyez très prudent lorsque vous adaptez des vues avec le décorateur csrf_exempt et ne le faites qu’en cas d’absolue nécessité.

Protection contre l’injection SQL

L’injection SQL est un type d’attaque où un utilisateur malveillant est capable d’exécuter du code SQL arbitraire sur une base de données. Il peut en résulter des suppressions d’enregistrements ou des divulgations de données.

En utilisant des requêtes Django de type QuerySet , le code SQL produit est proprement échappé par le pilote de base de données sous-jacent. Cependant, Django permet aussi aux développeurs d’écrire des requêtes brutes ou d’exécuter du code SQL personnalisé. Ces possibilités devraient être exploitées de manière parcimonieuse et il faut toujours prendre la précaution d’échapper proprement tout paramètre pouvant être contrôlé par l’utilisateur. De plus, il faut être prudent en utilisant extra() et RawSQL.

Protection contre le détournement de clic (« clickjacking »)

Le détournement de clic est un type d’attaque où un site malveillant intègre un autre site dans un cadre. Cette attaque peut amener un utilisateur à cliquer de manière non désirée pour effectuer des actions non volontaires sur le site ciblé.

Django intègre une protection contre le détournement de clic sous la forme de l’intergiciel X-Frame-Options qui, dans un navigateur qui le prend en charge, peut empêcher un site d’être affiché à l’intérieur d’un cadre. Il est possible de désactiver cette protection par vue ou de configurer la valeur exacte de l’en-tête envoyé.

Cet intergiciel est fortement recommandé pour tout site qui n’a pas besoin de voir ses pages affichées dans un cadre par des sites tiers ou qui n’en a besoin que pour une section limitée du site.

SSL/HTTPS

Le déploiement de votre site en HTTPS est toujours mieux pour la sécurité. Sans cela, il est possible que des utilisateurs malveillants du réseau interceptent des données d’authentification ou toute autre information transférée entre le client et le serveur et, dans certains cas, pour des attaquants réseau actifs, que des données soient modifiées au passage, dans l’une ou l’autre direction.

Si vous souhaitez profiter de la protection ajoutée par HTTPS et l’activer sur votre serveur, il peut être nécessaire de procéder à quelques étapes supplémentaires :

  • Si nécessaire, définissez SECURE_PROXY_SSL_HEADER, en prenant soin de bien comprendre les avertissements correspondants. Sinon, cela pourrait provoquer des vulnérabilités CSRF, et son application incorrecte peut aussi être dangereuse !

  • Définissez SECURE_SSL_REDIRECT à True, pour que les requêtes HTTP soient redirigées vers HTTPS.

    Prenez bonne note des mises en garde de SECURE_PROXY_SSL_HEADER. Dans le cas d’un serveur mandataire inverse, il peut être plus simple ou plus sûr de configurer le serveur Web principal pour qu’il fasse lui-même la redirection vers HTTPS.

  • Utilisez des cookies « sécurisés ».

    Si un navigateur se connecte initialement en HTTP, ce qui est le comportement par défaut de la plupart des navigateurs, il est possible que des cookies existants soient divulgués. Pour cette raison, vous devriez définir les réglages SESSION_COOKIE_SECURE et CSRF_COOKIE_SECURE à True. Cela indique au navigateur qu’il ne doit envoyer les cookies que par des connexions HTTPS. Notez que cela signifie que les sessions ne fonctionneront pas en HTTP et que la protection CSRF empêchera l’acceptation de données POST par HTTP (ce qui ne pose pas de problème si vous redirigez tout le trafic HTTP vers HTTPS).

  • Utilisez Sécurité de transport HTTP stricte (HSTS) (HSTS)

    HSTS is an HTTP header that informs a browser that all future connections to a particular site should always use HTTPS. Combined with redirecting requests over HTTP to HTTPS, this will ensure that connections always enjoy the added security of SSL provided one successful connection has occurred. HSTS may either be configured with SECURE_HSTS_SECONDS, SECURE_HSTS_INCLUDE_SUBDOMAINS, and SECURE_HSTS_PRELOAD, or on the Web server.

Validation de l’en-tête Host

Django utilise l’en-tête Host fourni par le client pour construire les URL dans certains cas. Même si ces valeurs sont vérifiées pour empêcher les attaques Cross Site Scripting, une valeur Host contrefaite peut être exploitée pour des attaques de type Cross-Site Request Forgery, d’empoisonnement de cache et d’empoisonnement de liens dans les courriels.

Comme même des configurations de serveur Web apparemment sûres sont susceptibles d’accepter des en-têtes Host contrefaits, Django valide les en-têtes Host en les comparant avec le réglage ALLOWED_HOSTS dans la méthode django.http.HttpRequest.get_host().

Cette validation ne s’applique qu’avec get_host() ; si votre code accède directement à l’en-tête Host dans request.META, vous outrepassez cette protection de sécurité.

Pour plus de détails, consultez la documentation complète de ALLOWED_HOSTS.

Avertissement

Des versions précédentes de ce document recommandaient de configurer le serveur Web pour s’assurer qu’il valide les en-têtes HTTP Host entrants. Même si c’est toujours recommandé, bien des configurations de serveurs Web bien connus paraissant valider l’en-tête Host ne le font pas toujours en réalité. Par exemple, même si Apache est configuré pour que votre site Django soit servi depuis un hôte virtuel autre que celui par défaut ayant défini ServerName, il est encore possible qu’une requête HTTP corresponde à cet hôte tout en fournissant un en-tête Host contrefait. C’est pourquoi Django demande dorénavant que ALLOWED_HOSTS soit défini explicitement plutôt que de se fier à la configuration du serveur Web.

En plus, Django exige que vous activiez explicitement la prise en charge de l’en-tête X-Forwarded-Host (via le réglage USE_X_FORWARDED_HOST) si votre configuration l’exige.

Sécurité des sessions

Tout comme les limites de CSRF exigeant qu’un site soit déployé de manière à ce que des utilisateurs non fiables n’aient pas accès à d’éventuels sous-domaines, django.contrib.sessions présente également certaines limites. Consultez la section sur la sécurité du guide thématique des sessions pour plus de détails.

Contenu envoyé par les utilisateurs

Note

Considérez le service des fichiers statiques par un service en nuage ou un CDN pour éviter certains de ces problèmes.

  • Si votre site accepte les envois de fichiers, il est fortement conseillé de limiter ces envois dans la configuration du serveur Web à une taille raisonnable afin d’empêcher des attaques par déni de service (DOS). Dans Apache, on peut le faire facilement en configurant la directive LimitRequestBody.

  • Si vous servez vous-même les fichiers statiques, soyez sûr que les gestionnaires comme mod_php d’Apache qui pourraient exécuter des fichiers statiques comme du code sont désactivés. Il n’est manifestement pas souhaitable que des utilisateurs puissent exécuter du code arbitraire en téléversant puis en accédant à un fichier spécialement prévu à cet effet.

  • La gestion des envois de fichiers par Django présente certaines vulnérabilités lorsque ces fichiers sont ensuite servis selon des pratiques non sécurisées. Plus particulièrement, un fichier HTML peut être téléversé comme image si le fichier contient un en-tête PNG valide suivi de code HTML malicieux. Ce fichier passera avec succès les vérifications effectuées par la bibliothèque de traitement d’image utilisée par Django (Pillow). Au moment où le fichier est ensuite affiché pour un utilisateur, il se peut qu’il soit affiché comme un fichier HTML en fonction du type et de la configuration du serveur Web.

    Il n’existe actuellement pas de solution technique à toute épreuve dans l’infrastructure Django pour valider de manière sûre tous les contenus de fichiers envoyés par les utilisateurs. Cependant, il existe un certain nombre de mesures à prendre pour diminuer les risques de telles attaques :

    1. Une catégorie d’attaques peut être évitée en servant toujours les contenus envoyés par les utilisateurs à partir d’un autre nom de domaine de premier ou de deuxième niveau. Cela évite les attaques bloquées par les protections same-origin policy telles que les scripts inter-sites. Par exemple, si votre site est servi par example.com, il serait imaginable de servir les contenus téléversés (cf. réglage MEDIA_URL) à partir d’un site nommé contenuutilisateur-example.com. Il n’est pas suffisant de servir le contenu à partir d’un sous-domaine tel que contenuutilisateur.example.com.

    2. En plus de cette mesure, les applications peuvent choisir de définir une liste des extensions de fichiers autorisées pour les fichiers téléversés par les utilisateurs et configurer le serveur Web pour qu’il n’accepte de servir que ces fichiers.

Thèmes de sécurité supplémentaires

Même si Django offre nativement de bonnes protections de sécurité, il est toujours important de déployer proprement les applications et de profiter des protections de sécurité du serveur Web, du système d’exploitation et d’autres composants.

  • Prenez soin de placer votre code Python en dehors de la racine du serveur Web. Ceci pour garantir que le code Python ne puisse pas être accidentellement servi en texte pur (ou exécuté accidentellement).

  • Prenez garde aux fichiers envoyés par les utilisateurs.

  • Django ne limite pas les requêtes d’authentification des utilisateurs. Pour se protéger des attaques en force brute contre le système d’authentification, il faut envisager le déploiement d’un complément Django ou d’un module du serveur Web pour limiter ces requêtes.

  • Gardez bien SECRET_KEY secrète.

  • C’est une bonne pratique que de limiter l’accès au système de cache et à la base de données par un pare-feu.

  • Jetez un œil à la liste Top 10 du projet Open Web Application Security (OWASP) qui identifie quelques vulnérabilités fréquentes dans les applications Web. Bien que Django possède des outils pour affronter certains de ces problèmes, d’autres doivent être pris en compte durant la conception de votre projet.

Back to Top