5 votes

Django + Caddy = Problèmes de protection CSRF

J'ai déployé une application Django 4 avec Daphne (ASGI) dans un conteneur docker. J'utilise Caddy comme proxy inverse devant. Tout fonctionne, sauf que je ne peux pas remplir de formulaire car la protection CSRF se déclenche. Donc pas de connexion admin, par exemple.

Je peux actuellement accéder à l'interface admin de deux manières :

  1. Directement via docker, via un port tunnellisé SSH
  2. À travers Caddy, qui redirige ensuite vers le conteneur Docker.

L'option 1 fonctionne. Je peux me connecter à l'interface admin comme si j'exécutais le serveur de développement localement. Tout fonctionne comme prévu.

Cependant, l'option 2 (proxy inverse de Caddy) ne fonctionne pas. Je peux accéder à Django et charger des pages, mais toute soumission de formulaire sera bloquée car la protection CSRF se déclenche.

La vérification CSRF a échoué. Requête abandonnée.

Raison donnée pour l'échec :
    La vérification de l'origine a échoué - https:// ne correspond à aucune origine de confiance.

Mon Caddyfile contient ceci :

 {
       reverse_proxy localhost:8088
}

localhost:8088 est le port exposé par mon conteneur docker.

Dans un effort pour éliminer les problèmes potentiels, j'ai défini les éléments suivants sur false dans mon fichier de configuration :

  • SECURE_SSL_REDIRECT (cause une boucle de redirection, probablement liée à la rétro-proxy)
  • SESSION_COOKIE_SECURE (je préférerais le définir sur True, mais je ne sais pas à ce stade)
  • CSRF_COOKIE_SECURE (même remarque)

Les seuls exemples Django-Caddy que j'ai pu trouver en ligne sont obsolètes et font référence à des versions plus anciennes de Caddy et/ou de Django. Django est déployé sur ASGI avec Daphne.

J'ai vu des publications suggérant de modifier CSRF_TRUSTED_ORIGINS, mais il ne semble pas logique que je doive ajouter un hôte qui est déjà dans la liste ALLOWED_HOSTS. Cela n'expliquerait pas non plus pourquoi cela fonctionne directement sur le conteneur docker, à moins que localhost soit un cas particulier pour CSRF.

Versions :

  • Caddy: 2.5.1
  • Django: 4.0.5
  • Daphne: 3.0.2
  • Python: 3.10.5

Avez-vous une idée de ce qui ne va pas, et comment je devrais procéder pour résoudre de tels problèmes ?

11voto

aspyct Points 757

Enfin découvert ce qui se passait.

Au départ, je voulais savoir quelle était la requête HTTP exacte envoyée de caddy à django:

sudo tcpdump -i lo -A -n port 8088

Cela a confirmé que:

  • les en-têtes Origin et Referer étaient correctement définis
  • le cookie csrftoken était correctement envoyé

Une fois que cela a été identifié, j'ai pu examiner le code de django. Plus précisément, cette fonction dans le middleware CSRF.

En conclusion:

  1. Caddy transfère la requête http vers django de manière non cryptée (donc non sécurisée entre caddy et django).
  2. Django considère cette requête non sécurisée
  3. La protection CSRF attend que l'en-tête Origin envoyé par le navigateur soit http:// car la requête n'est pas sécurisée. Dans mon cas, c'est https:// car mon navigateur communique avec Caddy via https
  4. Comme l'en-tête Origin ne correspond pas à ce que le middleware CSRF attend, la requête est rejetée

C'est en fait une correction simple.

Étant donné que nous savons que Caddy va toujours ignorer X-Forwarded-Proto du navigateur et le définir lui-même, nous pouvons ajouter SECURE_PROXY_SSL_HEADER au fichier settings.py dans django:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Et voilà!

Maintenant je peux également définir ces valeurs sur true:

  • SECURE_SSL_REDIRECT
  • SESSION_COOKIE_SECURE
  • CSRF_COOKIE_SECURE

EDIT Voici le Caddyfile, comme demandé:

service.mywebsite.com {
        reverse_proxy localhost:8088
}

0 votes

Pouvez-vous s'il vous plaît donner l'exemple de vos paramètres Caddyfile pour l'Origine et le Referer? Juste en définissant SECURE_PROXY_SSL_HEADER n'a pas fonctionné pour moi et je pense que cela a quelque chose à voir avec Caddy.

0 votes

@HermanMartinus Bien sûr, mais il n'y a rien de spécial à cela. Je vais éditer la réponse maintenant.

1 votes

La solution pour moi n'était pas du côté de Caddy, mais de définir USE_X_FORWARDED_HOST = True car il y a une incohérence entre l'Origine et le Référent sinon, provoquant Django à afficher une erreur d'insécurité.

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