Files
Forge-Engine/core/csrf.py
T
williamandClaude Sonnet 5 a52b244f27 Ajoute la protection CSRF sur tous les formulaires et requêtes AJAX
Un jeton unique par session (core/csrf.py, exposé côté Jinja via
csrf_token()) est vérifié sur toute requête non-GET par un before_request
(core/csrf_guard.py), dans le même esprit que core/auth_guard.py : une
seule garde globale plutôt que de toucher aux ~90 routes existantes une
par une.

L'app entière fait déjà transiter ses formulaires par fetch() : pjax.js
intercepte chaque <form> interne et le transforme lui-même en requête
fetch (aucun usage de l'attribut d'échappement data-no-pjax nulle part
dans le repo, confirmé par grep). Il suffit donc de patcher window.fetch
UNE SEULE FOIS (static/csrf_fetch.js) pour y ajouter automatiquement
l'en-tête X-CSRFToken sur toute requête non-GET, formulaires pjax comme
fetch() écrits à la main dans screen_edit.html/game_dashboard.html/
play.html — sans modifier un seul appel existant.

La vérification est désactivée quand app.config["TESTING"] est actif
(même convention que Flask-WTF/WTF_CSRF_ENABLED), pour ne pas avoir à
ajouter le jeton aux ~170 tests existants qui appellent les routes
directement via le client de test Flask. tests/test_csrf.py réactive
volontairement la garde pour la mettre à l'épreuve pour de vrai (GET
jamais bloqué, POST sans jeton/avec mauvais jeton -> 400, POST avec le
bon jeton via l'en-tête ou le champ de formulaire -> succès).

templates/play.html reçoit les mêmes deux balises que base.html car il
est autonome (ne l'étend pas, propre <html>/<head>).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 20:35:32 +02:00

25 lines
882 B
Python

"""Jeton CSRF — un seul jeton par SESSION (pas un par formulaire, comme le
ferait Flask-WTF) : suffisant ici et beaucoup plus simple à propager
partout où l'appli envoie une requête qui modifie quelque chose, que ce
soit un <form> classique (intercepté par pjax.js, voir static/pjax.js) ou
un fetch() construit à la main (screen_edit.html, game_dashboard.html,
play.html...) — voir static/csrf_fetch.js, qui l'ajoute automatiquement en
en-tête à CHAQUE fetch() non-GET de l'appli plutôt que de devoir modifier
individuellement chacun des nombreux appels existants."""
import secrets
from flask import session
from .flask_app import app
def get_csrf_token():
token = session.get("csrf_token")
if not token:
token = secrets.token_urlsafe(32)
session["csrf_token"] = token
return token
app.jinja_env.globals["csrf_token"] = get_csrf_token