# Documentation Django 3.1.9.dev

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

L’intergiciel et les balises de gabarit CSRF permettent de se protéger facilement contre les attaques de type Cross Site Request Forgeries. Ce type d’attaque se produit quand un site Web malveillant contient un lien, un bouton de formulaire ou un peu de JavaScript qui est destiné à effectuer une action sur votre site Web, en utilisant les informations d’identification d’un utilisateur connecté qui visite le site malveillant dans son navigateur. Un type d’attaque liée est également couverte : celle du « login CSRF », où un site attaquant piège le navigateur d’un utilisateur en se connectant à un site avec les informations d’identification de quelqu’un d’autre.

La première ligne de défense contre les attaques CSRF est de s’assurer que les requêtes GET (et les autres méthodes « sûres », telles que définies par RFC 7231#section-4.2.1) sont sans effet de bord. Les appels par des méthodes « non sûres », comme POST, PUT et DELETE, peuvent ensuite être protégés en suivant les étapes ci-dessous.

## Comment l’utiliser

Pour profiter de la protection CSRF dans les vues, procédez comme suit :

1. L’intergiciel CSRF est activé par défaut dans le réglage `MIDDLEWARE`. Si vous surchargez ce réglage, rappelez-vous que `'django.middleware.csrf.CsrfViewMiddleware'` doit figurer avant les intergiciels qui comptent sur le fait que les attaques CSRF ont déjà été contrées.

   Si vous le désactivez, ce qui n’est pas recommandé, vous pouvez utiliser `csrf_protect()` sur certaines vues que vous souhaitez protéger (voir ci-dessous).

2. Dans tout gabarit qui utilise un formulaire POST, utilisez la balise de gabarit `csrf_token` à l’intérieur de la balise HTML `<form>` si le formulaire renvoie vers une URL interne, par exemple :

       <form method="post">{% csrf_token %}

   Par contre, il ne faut pas le faire pour les formulaires POST qui ciblent des URL externes, car cela entraînerait la divulgation du jeton CSRF, et conduirait ainsi à une vulnérabilité.

3. Dans les fonctions de vue correspondantes, vérifiez que `RequestContext` est utilisé pour produire la réponse afin que `{% csrf_token %}` fonctionne correctement. Si vous utilisez la fonction `render()`, les vues génériques ou les applications contribuées, il n’y a pas de soucis à se faire car toutes ces vues utilisent `RequestContext`.

### AJAX

Même si la méthode ci-dessus peut être utilisée pour les requêtes AJAX POST, elle présente quelques inconvénients : il ne faut pas oublier de passer le jeton CSRF en même temps que les données POST à ​​chaque requête POST. Pour cette raison, il y a une autre méthode : sur chaque XMLHttpRequest, définissez un élément d’en-tête `X-CSRFToken` (tel qu’indiqué par le réglage `CSRF_HEADER_NAME`) ayant la même valeur que le jeton CSRF. C’est souvent plus simple, parce que de nombreuses bibliothèques JavaScript fournissent des points d’extension qui permettent d’ajouter des éléments d’en-tête pour chaque requête.

Il faut d’abord obtenir le jeton CSRF. La façon de faire dépend de l’activation ou non des réglages `CSRF_USE_SESSIONS` et `CSRF_COOKIE_HTTPONLY`.

#### Acquisition du jeton si `CSRF_USE_SESSIONS` et `CSRF_COOKIE_HTTPONLY` valent `False`

La source recommandée pour le jeton est le cookie `csrftoken`, qui sera présent si vous avez activé la protection CSRF pour votre vue, comme indiqué ci-dessus.

Le cookie CSRF est nommé `csrftoken` par défaut, mais vous pouvez modifier ce nom via le réglage `CSRF_COOKIE_NAME`.

Vous pouvez obtenir le jeton comme ceci :

    function getCookie(name) {
        let cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            const cookies = document.cookie.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    const csrftoken = getCookie('csrftoken');

Le code ci-dessus pourrait être simplifié en utilisant la bibliothèque JavaScript Cookie pour remplacer `getCookie`:

    const csrftoken = Cookies.get('csrftoken');

Note

Le jeton CSRF est également présent dans le DOM, mais seulement s’il est explicitement inclus à l’aide de la balise `csrf_token` dans un gabarit. Le cookie contiendra le jeton standard ; le `CsrfViewMiddleware` préfèrera le cookie au jeton du DOM. De toute façon, vous êtes assuré d’avoir le cookie si le jeton est présent dans le DOM, il est donc préférable d’utiliser le cookie !

Avertissement

Si la vue n’utilise pas un gabarit contenant la balise `csrf_token`, Django peut ne pas définir le cookie CSRF. Cette situation apparaît souvent dans les cas où les formulaires sont ajoutés dynamiquement à la page. Pour résoudre ce problème, Django fournit un décorateur de vue qui force l’utilisation du cookie : `ensure_csrf_cookie()`.

#### Acquisition du jeton si `CSRF_USE_SESSIONS` ou `CSRF_COOKIE_HTTPONLY` vaut `True`

Si vous activez `CSRF_USE_SESSIONS` ou `CSRF_COOKIE_HTTPONLY`, vous devez inclure le jeton CSRF dans le code HTML et lire le jeton dans le DOM en JavaScript :

    {% csrf_token %}
    <script>
    const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
    </script>

#### Définition du jeton pour une requête AJAX

Enfin, vous devrez renseigner l’en-tête de votre requête AJAX. En utilisant l’API fetch() :

    const request = new Request(
        /* URL */,
        {headers: {'X-CSRFToken': csrftoken}}
    );
    fetch(request, {
        method: 'POST',
        mode: 'same-origin'  // Do not send CSRF token to another domain.
    }).then(function(response) {
        // ...
    });

### Utilisation de CSRF dans les gabarits Jinja2

Le moteur de gabarit `Jinja2` de Django ajoute `{{ csrf_input }}` au contexte de tous les gabarits, ce qui est équivalent à `{% csrf_token %}` dans le langage de gabarit de Django. Par exemple :

    <form method="post">{{ csrf_input }}

### La méthode du décorateur

Plutôt que d’ajouter `CsrfViewMiddleware` comme une protection générale, vous pouvez utiliser le décorateur `csrf_protect`, qui offre exactement la même fonctionnalité, sur les vues particulières qui ont besoin de la protection. Ce décorateur doit être utilisé à la fois sur les vues qui insèrent le jeton CSRF dans leur rendu, et sur celles qui acceptent les données de formulaire POST. (Il s’agit souvent de la même fonction de vue, mais pas toujours).

Le recours à l’utilisation seule du décorateur n’est pas recommandé, car si vous oubliez de l’utiliser, vous aurez un trou de sécurité. La stratégie « ceinture et bretelles » qui consiste à utiliser les deux convient tout à fait et n’entraînera qu’une surcharge minimale.

`csrf_protect`(view)

  Décorateur qui fournit la protection similaire à l’intergiciel `CsrfViewMiddleware` pour une vue.

  Utilisation :

      from django.shortcuts import render
      from django.views.decorators.csrf import csrf_protect

      @csrf_protect
      def my_view(request):
          c = {}
          # ...
          return render(request, "a_template.html", c)

  Si vous utilisez des vues fondées sur les classes, vous pouvez vous référer à la Décoration des vues fondées sur les classes.

## Requêtes rejetées

Par défaut, une réponse de type « 403 Forbidden » est renvoyée à l’utilisateur si une requête entrante ne satisfait pas les contrôles effectués par `CsrfViewMiddleware`. Ça ne devrait généralement apparaître que lorsqu’il s’agit d’une véritable attaque de type « Cross Site Request Forgery », ou lorsqu’en raison d’une erreur de programmation, le jeton CSRF n’a pas été inclus dans un formulaire de type POST.

La page d’erreur n’est toutefois pas très sympathique, de sorte que vous pouvez fournir votre propre vue pour traiter cette condition. Pour ce faire, définissez le réglage `CSRF_FAILURE_VIEW`.

Les échecs CSRF sont journalisés comme avertissements dans le journaliseur django.security.csrf.

## Fonctionnement

La protection CSRF est basée sur les éléments suivants :

1. Un cookie CSRF qui est basé sur une valeur secrète aléatoire auquel les autres sites n’auront pas accès.

   Ce cookie est créé par l’intergiciel `CsrfViewMiddleware`. Il est envoyé avec chaque réponse qui a appelé `django.middleware.csrf.get_token()` (la fonction utilisée en interne pour récupérer le jeton CSRF), s’il n’a pas déjà été défini pour la requête.

   Afin de protéger contre les attaques BREACH, le jeton n’est pas simplement la valeur secrète ; un masque aléatoire est préfixé à la valeur et utilisé pour le brouiller.

   Pour des raisons de sécurité, la valeur secrète est modifiée chaque fois qu’un utilisateur se connecte.

2. Un champ de formulaire masqué nommé `csrfmiddlewaretoken` et présent dans tous les formulaires POST sortants. La valeur de ce champ est, encore une fois, la valeur secrète avec un masque qui est ajouté et utilisé pour le brouiller. Le masque est régénéré à chaque appel à `get_token()` afin que la valeur de champ de formulaire soit modifiée dans chacune des réponses.

   Cette action est effectuée par la balise de gabarit.

3. Pour toutes les requêtes entrantes qui n’utilisent pas les méthodes HTTP GET, HEAD, OPTIONS ou TRACE, un cookie CSRF doit être présent, et le champ « csrfmiddlewaretoken » doit être présent et correct. Si ce n’est pas le cas, l’utilisateur obtiendra une erreur 403.

   Lors de la validation de la valeur de champ `csrfmiddlewaretoken`, seule la valeur secrète, et non pas le jeton complet, est comparée avec la valeur secrète du contenu du cookie. Cela permet d’utiliser des jetons qui changent constamment. Alors que chaque requête peut utiliser son propre jeton, la valeur secrète reste commune à toutes.

   Cette vérification est effectuée par l’intergiciel `CsrfViewMiddleware`.

4. De plus, pour les requêtes HTTPS, le contrôle strict du référant est effectué par `CsrfViewMiddleware`. Cela signifie que même si un sous-domaine peut définir ou modifier des cookies pour votre domaine, il ne peut pas forcer un utilisateur à envoyer des données à votre application car cette requête ne viendrait pas de votre domaine exact.

   Cela protège aussi contre une attaque de type « Man-In-The-Middle » qui est possible sous HTTPS lors de l’utilisation d’une valeur secrète indépendante de la session, parce que les en-têtes HTTP `Set-Cookie` sont (malheureusement) acceptés par les clients, même quand ils parlent à un site en HTTPS. (La vérification du référant n’est pas faite pour les requêtes HTTP car la présence de l’en-tête `Referer` n’est pas suffisamment fiable sous HTTP.)

   Si le réglage `CSRF_COOKIE_DOMAIN` est défini, le référant est comparé avec lui. Il est possible d’autoriser les requêtes inter-domaines en incluant un point en premier. Par exemple, `CSRF_COOKIE_DOMAIN = '.exemple.com'` autorise les requêtes POST depuis `www.exemple.com` et `api.exemple.com`. Si le réglage n’est pas défini, le référant doit alors correspondre à l’en-tête HTTP `Host`.

   L’extension des référants acceptés au-delà de l’hôte courant ou du domaine du cookie peut se faire avec le réglage `CSRF_TRUSTED_ORIGINS`.

Cela garantit que seuls les formulaires originaires de domaines de confiance peuvent être utilisés pour renvoyer des données avec une requête POST.

Les requêtes GET sont volontairement ignorées (ainsi que les autres requêtes définies comme « sûres » par la RFC 7231#section-4.2.1). Ces requêtes ne devraivent jamais avoir d’effets secondaires potentiellement dangereux, et de cette manière une attaque CSRF avec une requête GET doit être inoffensive. La RFC 7231#section-4.2.1 définit les méthodes POST, PUT et DELETE comme « non sûres », et toutes les autres méthodes sont aussi supposées être dangereuses, pour que la protection soit maximale.

La protection CRSF ne peut pas protéger contre les attaques de « l’homme du milieu », c’est pourquoi il faut utiliser HTTPS avec Sécurité de transport HTTP stricte (HSTS). Il suppose également la validation de l’en-tête HOST et que le site ne comporte pas de vulnérabilités de scripts inter-sites (parce que ce type de vulnérabilité permet déjà à un attaquant de faire ce qu’une vulnérabilité CSRF permet de faire, et plus encore).

Suppression de l’en-tête `Referer`

Pour éviter de divulguer l’URL référent à des sites tiers, il peut être souhaitable de désactiver le référent dans les balises `<a>` de votre site. Par exemple, il est possible d’utiliser la balise `<meta name="referrer" content="no-referrer">` ou d’inclure l’en-tête `Referrer-Policy: no-referrer`. En raison du contrôle strict du référent dans la protection CSRF pour les requêtes HTTPS, ces techniques produisent des échecs CSRF pour les requêtes de méthodes « non sûres ». Il est préférable d’utiliser des alternatives telles que `<a rel="noreferrer" ...>"` pour les liens vers des sites tiers.

## Mise en cache

Si la balise de gabarit `csrf_token` est utilisée par un gabarit (ou que la fonction `get_token` est appelée d’une autre façon), l’intergiciel `CsrfViewMiddleware` ajoute un cookie et un en-tête `Vary: Cookie` à la réponse. Cela signifie que l’intergiciel fonctionnera bien avec l’intergiciel de cache s’il est utilisé conformément aux instructions (`UpdateCacheMiddleware` doit être placé dans les réglages avant tout autre intergiciel).

Toutefois, si vous utilisez des décorateurs de cache sur des vues individuelles, l’intergiciel CSRF n’aura pas encore pu définir l’en-tête Vary ou le cookie CSRF, et la réponse sera mise en cache sans l’un ni l’autre. Dans ce cas, sur les vues qui nécessitent qu’un jeton CSRF soit inséré, vous devez utiliser le décorateur de fonction `django.views.decorators.csrf.csrf_protect()` en premier :

    from django.views.decorators.cache import cache_page
    from django.views.decorators.csrf import csrf_protect

    @cache_page(60 * 15)
    @csrf_protect
    def my_view(request):
        ...

Si vous utilisez des vues fondées sur les classes, vous pouvez vous référer à la Décoration des vues fondées sur les classes.

## Tests

Généralement, `CsrfViewMiddleware` gêne les tests des fonctions de vues, parce que le jeton CSRF doit être envoyé avec chaque requête POST. Le client HTTP de Django utilisé pour les tests a donc été modifié afin de marquer automatiquement les requêtes et ainsi d’informer l’intergiciel et le décorateur `csrf_protect` de manière à ce qu’ils ne rejettent pas ces requêtes. À tous les autres égards (par exemple, l’envoi des cookies, etc.), le comportement durant les tests est identique.

Si pour une raison quelconque vous voulez que le client HTTP utilisé pour les tests effectue des contrôles CSRF, vous pouvez créer une instance du client de test qui applique les vérifications CSRF :

    >>> from django.test import Client
    >>> csrf_client = Client(enforce_csrf_checks=True)

## Limitations

Les sous-domaines d’un site peuvent placer des cookies sur le client pour l’ensemble du domaine. En définissant le cookie et en utilisant le jeton correspondant, les sous-domaines seront en mesure de contourner la protection CSRF. La seule façon d’éviter cela est de s’assurer que les sous-domaines sont contrôlés par des utilisateurs de confiance (ou, au moins ne sont pas en mesure de définir des cookies). Notez que même sans CSRF, il existe d’autres vulnérabilités, comme la fixation de session, qui font que donner des sous-domaines à des tierces parties non sûres est une mauvaise idée ; ces vulnérabilités ne peuvent pas facilement être résolues avec les navigateurs actuels.

## Cas particuliers

Certaines vues peuvent avoir des exigences inhabituelles qui impliquent qu’elles ne correspondent pas au modèle normal envisagé ici. Un certain nombre d’utilitaires peuvent être utiles dans ces situations. Les scénarios qui pourraient alors être nécessaires sont décrits dans la section suivante.

### Utilitaires

Les exemples ci-dessous s’appliquent à des vues basées sur des fonctions. Si vous utilisez des vues fondées sur les classes, vous pouvez vous référer à la Décoration des vues fondées sur les classes.

`csrf_exempt`(view)

  Ce décorateur marque une vue comme étant exempte de la protection assurée par l’intergiciel. Exemple :

      from django.http import HttpResponse
      from django.views.decorators.csrf import csrf_exempt

      @csrf_exempt
      def my_view(request):
          return HttpResponse('Hello world')

`requires_csrf_token`(view)

  Normalement, la balise de gabarit `csrf_token` ne fonctionnera pas si `CsrfViewMiddleware.process_view` ou un équivalent comme `csrf_protect` n’a pas été utilisé. Le décorateur de vue `requires_csrf_token` peut être utilisé pour s’assurer que la balise de gabarit fonctionne. Ce décorateur fonctionne de façon similaire à `csrf_protect`, mais ne rejette jamais une demande entrante.

  Exemple :

      from django.shortcuts import render
      from django.views.decorators.csrf import requires_csrf_token

      @requires_csrf_token
      def my_view(request):
          c = {}
          # ...
          return render(request, "a_template.html", c)

`ensure_csrf_cookie`(view)

  Ce décorateur force une vue à envoyer le cookie CSRF.

### Scénarios

#### La protection CSRF doit être désactivée pour quelques vues

La plupart des vues nécessitent une protection CSRF, mais quelques-unes n’en ont pas besoin.

Solution : plutôt que de désactiver l’intergiciel et d’appliquer `csrf_protect` à toutes les vues qui en ont besoin, activez l’intergiciel et utilisez `csrf_exempt()`.

#### CsrfViewMiddleware.process_view non utilisé

Il y a des cas où `CsrfViewMiddleware.process_view` n’aura pas été exécuté avant votre vue - les gestionnaires d’erreurs 404 et 500, par exemple - mais vous avez quand même besoin du jeton CSRF dans un formulaire.

Solution : utilisez `requires_csrf_token()`

#### Une vue non protégée nécessite le jeton CSRF

Certaines vues peuvent ne pas être protégées, peut-être exemptées par `csrf_exempt`, mais ont tout de même besoin d’inclure le jeton CSRF.

Solution : utilisez `csrf_exempt()` suivi de `requires_csrf_token()` (c’est à dire que `requires_csrf_token` doit être le décorateur le plus à l’intérieur).

#### Une vue a besoin de protection pour un chemin particulier

Une vue a besoin de protection CSRF seulement quand un certain nombre de conditions sont remplies, et ne doit pas être protégée le reste du temps.

Solution : utilisez `csrf_exempt()` pour l’ensemble de la fonction de vue, et `csrf_protect()` spécifiquement pour le chemin qui doit être protégé. Exemple :

    from django.views.decorators.csrf import csrf_exempt, csrf_protect

    @csrf_exempt
    def my_view(request):

        @csrf_protect
        def protected_path(request):
            do_something()

        if some_condition():
           return protected_path(request)
        else:
           do_something_else()

#### Une page utilise de l’AJAX sans aucun formulaire HTML

Une page effectue une requête POST via AJAX, et cette page n’a pas de formulaire HTML avec une balise `csrf_token` qui provoquerait la transmission du cookie CSRF.

Solution : utilisez `ensure_csrf_cookie()` sur la vue qui envoie la page.

## Applications intégrées et applications réutilisables

Comme il est possible pour le développeur de désactiver l’intergiciel `CsrfViewMiddleware`, toutes les vues concernées dans les applications « contrib » de Django utilisent le décorateur `csrf_protect` pour garantir la protection de ces applications contre les attaques CSRF. Il est recommandé que les développeurs d’autres applications réutilisables qui souhaitent offrir les mêmes garanties utilisent également le décorateur `csrf_protect` sur leurs vues.

## Réglages

Un certain nombre de réglages peuvent être utilisés pour contrôler le comportement anti-CSRF de Django :

- `CSRF_COOKIE_AGE`
- `CSRF_COOKIE_DOMAIN`
- `CSRF_COOKIE_HTTPONLY`
- `CSRF_COOKIE_NAME`
- `CSRF_COOKIE_PATH`
- `CSRF_COOKIE_SAMESITE`
- `CSRF_COOKIE_SECURE`
- `CSRF_FAILURE_VIEW`
- `CSRF_HEADER_NAME`
- `CSRF_TRUSTED_ORIGINS`
- `CSRF_USE_SESSIONS`

## Questions fréquentes

### Est-ce que l’envoi d’une paire de jetons CSRF arbitraires (cookie et données POST) est une vulnérabilité ?

Non, délibérément pas. Sans attaque de « l’homme du milieu », il n’existe aucune possibilité pour un attaquant d’envoyer un cookie de jeton CSRF à destination du navigateur de sa victime ; une attaque réussie devrait pouvoir obtenir le cookie du navigateur de la victime par XSS ou autre moyen similaire, auquel cas l’attaquant n’a généralement pas besoin d’attaquer par CSRF.

Certains outils d’audit de sécurité le signalent comme un problème, mais comme mentionné ci-dessus, un attaquant ne peut pas voler un cookie CSRF du navigateur d’un utilisateur. Pouvoir « voler » ou modifier son propre jeton à l’aide de Firebug, des outils de développement Chrome, etc. ne signifie pas qu’il s’agit d’une vulnérabilité.

### Est-il problématique que la protection CSRF de Django n’est pas liée à une session par défaut ?

Non, délibérément pas. Le fait de ne pas lier la protection CSRF à une session permet d’utiliser la protection sur des sites tels que pastebin qui autorisent des envois de données par des utilisateurs anonymes et qui n’ont pas de session.

Si vous souhaitez stocker le jeton CSRF dans la session de l’utilisateur, définissez le réglage `CSRF_USE_SESSIONS`.

### Pourquoi un utilisateur peut-il recevoir une erreur de validation CSRF après s’être connecté ?

Pour des raisons de sécurité, les jetons CSRF subissent une rotation lors de chque connexion d’utilisateur. Toute page contenant un formulaire généré avant une connexion possédera un ancien jeton CSRF non valide et devra être rechargée. Cela peut arriver si un utilisateur utilise le bouton « Retour » après une connexion ou s’il se connecte dans un autre onglet du navigateur.