CSRF avec Django, React+Redux avec Axios

c'est un projet éducatif, pas pour la production. Je n'avais pas l'intention d'avoir des logins utilisateurs dans le cadre de cela.

puis-je faire des appels postaux à Django avec un jeton CSRF sans avoir de login utilisateur? Puis-je le faire sans utiliser jQuery? Je suis hors de ma portée ici, et sûrement en train de confondre quelques concepts.

pour le côté JavaScript, j'ai trouvé ceci redux-csrf package. Je ne sais pas comment le combiner avec mon POST action à l'aide d' 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 sur le travail général avec des vues basées sur la classe.

Voici mon avis pour l'instant:

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 à se soucier de cela pour le moment, mais cela ne semble pas être comment cela fonctionne.

j'ai ajouté {% csrf_token %} pour mon modèle.

C'est mon getCookie méthode (vol à partir de Django docs):

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 j'ai besoin de changer l'Axios CSRF info:

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

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

Où puis-je coller le jeton actuel, la valeur que j'obtiens en appelant <!--8?

26
demandé sur Reed Dunkle 2016-08-31 19:21:27

7 réponses

Il y a trois façons. Vous pouvez inclure manuellement le token dans l'en-tête de chaque appel axios, vous pouvez définir xsrfHeaderName dans chaque appel, ou définir une valeur par défaut xsrfHeaderName.

1. 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 xsrfHeaderName à l'appel:

Ajouter ceci:

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

Puis dans votre settings.py fichier, ajoutez cette ligne:

CSRF_COOKIE_NAME = "XSRF-TOKEN"

3. Le réglage par défaut des en-têtes [1]

au lieu 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";

Puis dans votre settings.py le fichier, ajoutez cette ligne:

CSRF_COOKIE_NAME = "XSRF-TOKEN"

EDIT: apparemment, cela fonctionne un peu différemment avec Safari [2]

[1] à Partir de Dave Merwin


la confusion:

Django Docs

tout D'abord, tout le passage de la Django docs que James Evans référencés:

...sur chaque XMLHttpRequest, définissez un en-tête X-CSRFToken personnalisé la valeur du jeton CSRF. C'est souvent plus facile, parce que beaucoup de JavaScript les cadres fournissent des crochets qui permettent aux en-têtes d'être mis sur chaque demande.

dans un premier temps, vous devez obtenir le jeton CSRF lui-même. Recommandé la source du token est le cookie csrftoken, qui sera défini si vous avez activé la protection CSRF pour vos vues comme décrit ci-dessus.

Remarque:

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

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


Axios Docs

C'est à partir de la Axios docs. Il indique que vous définissez le nom du cookie qui contient le 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

Termes

comme indiqué dans ma question, vous accédez cookies avec document.cookie. Le seul cookie que j'ai est le jeton CSRF que j'ai mis dans le modèle Django. Voici un exemple:

csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU

il y a quelques concepts qui sont jetés dans ces docs qui deviennent confus:

  • le nom du cookie qui contient le token CSRF. Dans Django c'est par défaut csrftoken, qui est sur le côté gauche du signe égal dans le cookie.
  • le jeton réel. C'est tout sur le côté droit de le signe égal dans le cookie.
  • l'en-tête http qui contient la valeur du token.

Choses que j'ai essayé cela ne fonctionne pas: 1,2

24
répondu Reed Dunkle 2017-06-12 13:01:42

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

DOESN't WORK IN APPLE Safari on Mac OS

la solution pour MAC Safari est facile,il suffit de changer XCSRF-TOKENcsrftoken

Donc, dans js-code devrait être:

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