59 votes

CSRF avec Django, React+Redux en utilisant Axios

Il s'agit d'un projet éducatif, non destiné à la production. Je n'avais pas l'intention d'avoir des connexions d'utilisateurs dans le cadre de ce projet.

Puis-je faire des appels POST à Django avec un jeton CSRF sans avoir de connexion d'utilisateur ? Puis-je le faire sans utiliser jQuery ? Je ne suis pas à la hauteur de la situation et j'ai sûrement confondu certains concepts.

Pour le côté JavaScript, j'ai trouvé ceci redux-csrf paquet. Je ne suis pas sûr de savoir comment le combiner avec ma POST action en utilisant Axios :

export const addJob = (title, hourly, tax) => {
  console.log("Trying to addJob: ", title, hourly, tax)
  return (dispatch) => {
    dispatch(requestData("addJob"));
    return axios({
      method: 'post',
      url: "/api/jobs",
      data: {
        "title": title,
        "hourly_rate": hourly,
        "tax_rate": tax
      },
      responseType: 'json'
    })
      .then((response) => {
        dispatch(receiveData(response.data, "addJob"));
      })
      .catch((response) => {
        dispatch(receiveError(response.data, "addJob"));
      })
  }
};

Du côté de Django, j'ai lu cette documentation sur CSRF, et este sur le fait de travailler généralement avec des vues basées sur la classe.

Voici ce que j'en pense jusqu'à présent :

class JobsHandler(View):

    def get(self, request):
        with open('./data/jobs.json', 'r') as f:
            jobs = json.loads(f.read())

        return HttpResponse(json.dumps(jobs))

    def post(self, request):
        with open('./data/jobs.json', 'r') as f:
            jobs = json.loads(f.read())

        new_job = request.to_dict()
        id = new_job['title']
        jobs[id] = new_job

        with open('./data/jobs.json', 'w') as f:
            f.write(json.dumps(jobs, indent=4, separators=(',', ': ')))

        return HttpResponse(json.dumps(jobs[id]))

J'ai essayé d'utiliser le csrf_exempt décorateur juste pour ne pas avoir à s'inquiéter de cela pour l'instant, mais cela ne semble pas être la façon dont cela fonctionne.

J'ai ajouté {% csrf_token %} à mon modèle.

C'est mon getCookie (volé dans la documentation de Django) :

function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var 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;
}

J'ai lu que je dois changer l'info CSRF d'Axios :

var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");

axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"

Où dois-je mettre le jeton réel, la valeur que j'obtiens en appelant getCookie('csrftoken') ?

0 votes

Vous devez lire la valeur du cookie "csrftoken" et définir la même valeur comme en-tête pour "X-CSRFToken". La mise en œuvre de la récupération du cookie et de la définition de l'en-tête changera si vous ne souhaitez pas utiliser Jquery, mais les principes de base restent les mêmes.

62voto

Reed Dunkle Points 978

Il y a trois façons de procéder. Vous pouvez inclure manuellement le jeton dans l'en-tête de chaque appel axios, vous pouvez définir la fonction xsrfHeaderName dans chaque appel, ou vous définissez une xsrfHeaderName .

1. L'ajouter manuellement

Disons que vous avez la valeur du jeton stockée dans une variable appelée csrfToken . Définissez les en-têtes dans votre appel axios :

// ...
method: 'post',
url: '/api/data',
data: {...},
headers: {"X-CSRFToken": csrfToken},
// ...

2. Réglage de xsrfHeaderName dans l'appel :

Ajoutez ceci :

// ...
method: 'post',
url: '/api/data',
data: {...},
xsrfHeaderName: "X-CSRFToken",
// ...

Alors dans votre settings.py ajoutez cette ligne :

CSRF_COOKIE_NAME = "XSRF-TOKEN"

3. Définition des en-têtes par défaut [1]

Plutôt que de définir l'en-tête dans chaque appel, vous pouvez définir des en-têtes par défaut pour axios.

Dans le fichier où vous importez axios pour faire l'appel, ajoutez ceci sous vos importations :

axios.defaults.xsrfHeaderName = "X-CSRFToken";

Alors dans votre settings.py ajoutez cette ligne :

CSRF_COOKIE_NAME = "XSRF-TOKEN"

Modifier ( 10 juin 2017 ) : L'utilisateur @yestema dit que cela fonctionne légèrement différemment avec Safari [2]

Modifier ( 17 avril 2019 ) : L'utilisateur @GregHolst indique que la solution Safari ci-dessus ne fonctionne pas pour lui. À la place, il a utilisé la solution n° 3 ci-dessus pour Safari 12.1 sur MacOS Mojave. ( des commentaires )

Modifier ( 17 février 2019 ) : Vous devrez peut-être aussi définir [3] :

axios.defaults.withCredentials = true

Question : Cette section suivante est-elle utile à quelqu'un ? Je me demande si cette réponse pourrait être améliorée en n'incluant que les solutions. Faites-moi savoir si vous avez une opinion, s'il vous plaît.

La confusion :

Docs Django

Tout d'abord, le passage entier du Documentation sur Django que James Evans référencé :

...sur chaque XMLHttpRequest, définissez un en-tête X-CSRFToken personnalisé à la valeur du jeton CSRF. valeur du jeton CSRF. C'est souvent plus facile, car de nombreux frameworks JavaScript fournissent des crochets qui permettent de définir les en-têtes à chaque requête. requête.

Dans un premier temps, vous devez obtenir le jeton CSRF lui-même. La source recommandée source recommandée pour le jeton est le cookie csrftoken, qui sera défini si vous avez activé la protection CSRF pour vos vues comme indiqué ci-dessus.

Note

Le cookie de jeton CSRF est nommé csrftoken par défaut, mais vous pouvez contrôler le nom du cookie via le paramètre CSRF_COOKIE_NAME.

Le nom de l'en-tête CSRF est HTTP_X_CSRFTOKEN par défaut, mais vous pouvez mais vous pouvez le personnaliser en utilisant le paramètre CSRF_HEADER_NAME.


Docs Axios

Cela vient du Documents d'Axios . Il indique que vous avez défini le nom du cookie qui contient l'adresse de l'utilisateur. csrftoken et le nom de l'en-tête ici :

  // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
  xsrfCookieName: 'XSRF-TOKEN', // default

  // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
  xsrfHeaderName: 'X-XSRF-TOKEN', // default

Conditions

Comme indiqué dans ma question, vous accédez aux cookies avec document.cookie . Le seul cookie dont je dispose est le jeton CSRF que j'ai placé dans le modèle Django. Voici un exemple :

csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU

Il y a quelques concepts lancés dans ces documents qui peuvent prêter à confusion :

  • Le nom du cookie qui contient le jeton CSRF. Dans Django, il s'agit par défaut de csrftoken qui se trouve à gauche du signe égal dans le cookie.
  • Le jeton réel. C'est tout ce qui se trouve à droite du signe égal dans le cookie.
  • L'en-tête http qui porte la valeur du jeton.

Les choses que j'ai essayées et qui n'ont pas marché : 1 , 2

0 votes

Il y a quelques années, je travaillais sur ce sujet et j'ai découvert l'approche n°2. Je n'ai pas utilisé Django depuis. Si ma réponse contient des informations périmées, faites-le moi savoir et je la mettrai à jour.

0 votes

L'option 3 fonctionne pour moi, mais pas l'option présentée ci-dessous pour Safari.

1 votes

@ReedDunkle Oui, cela fonctionne également avec Safari 12.1 sous MacOS Mojave. Au début, je n'ai pas essayé votre option3 car je pensais aller directement à la réponse de yestema, mais c'était manifestement une mauvaise méthode pour moi.

24voto

yestema Points 626

J'ai découvert, que axios.defaults.xsrfCookieName = "XCSRF-TOKEN"; et CSRF_COOKIE_NAME = "XCSRF-TOKEN"

NE FONCTIONNE PAS DANS APPLE Safari sur Mac OS

La solution pour MAC Safari est simple, juste changer XCSRF-TOKEN a csrftoken

Donc, en js-code devrait être :

    import axios from 'axios';
    axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
    axios.defaults.xsrfCookieName = "csrftoken";

Dans settings.py :

    CSRF_COOKIE_NAME = "csrftoken"

1 votes

Bien vu. J'ai ajouté un lien vers cette réponse dans la réponse principale.

9 votes

CSRF_COOKIE_NAME La valeur par défaut est 'csrftoken' donc vous n'avez pas besoin de modifier settings.py

15voto

krescruz Points 56

Cette configuration fonctionne pour moi sans problèmes Config axios CSRF django

import axios from 'axios'

/**
 * Config global for axios/django
 */
axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = 'csrftoken'

export default axios

5voto

cran_man Points 21

La "méthode facile" a presque fonctionné pour moi. Cela semble fonctionner :

import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "XCSRF-TOKEN";

Et dans le fichier settings.py :

CSRF_COOKIE_NAME = "XCSRF-TOKEN"

1 votes

Bienvenue à SO ! Veuillez visiter comment rédiger une réponse Vous avez fourni une réponse à une ancienne question qui a déjà une réponse très détaillée, approuvée et approuvée par de nombreuses personnes. Est-ce que votre fonctionne presque réponse apportent quelque chose d'utile aux autres qui n'a pas encore été détaillé ?

2voto

James Evans Points 505

Vous pourriez ajouter manuellement le jeton CSRF fourni par Django dans toutes vos demandes de publication, mais c'est ennuyeux.

De la Documentation sur Django :

Alors que la méthode ci-dessus ( définir manuellement le jeton CSRF ) peut être utilisé pour les requêtes AJAX POST, mais il présente quelques inconvénients : vous devez vous souvenir de transmettre le jeton CSRF en tant que données POST à chaque requête POST. Pour cette raison, il existe une méthode alternative : sur chaque XMLHttpRequest, définissez un en-tête X-CSRFToken personnalisé à la valeur du jeton CSRF. Cette méthode est souvent plus facile, car de nombreux cadres JavaScript fournissent des crochets qui permettent de définir les en-têtes à chaque requête.

La documentation contient un code que vous pouvez utiliser pour extraire le jeton CSRF du cookie CSRF et l'ajouter à l'en-tête de votre requête AJAX.

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