Bonjour,
Vous pouvez augmenter la durée de la session si 20 minutes n'est pas assez long.
Cdt
Erreur 'Token POST invalide'
GestSup: 3.2.53 | Debian: 12 | Apache: 2.4.59 | MariaDB: 11.5.2 | PHP: 8.3 | https://doc.gestsup.fr/
- RodrigueLoL
- Gsup LEVEL 3
- Messages : 55
- Enregistré le : mer. 28 juin 2017 11:27
- Contact :
Sur notre base le temps de déconnexion est déjà configuré à 1400 min.
Serveur : Debian 12 | GestSup : 3.2.59 | Apache : 2.4.65 | PHP : 8.4.14 | MariaDB : 10.11.14 | Tickets : 84 000+ | Techniciens : 5
Pouvez Vous transmettre une impression écran de votre page système.
GestSup: 3.2.53 | Debian: 12 | Apache: 2.4.59 | MariaDB: 11.5.2 | PHP: 8.3 | https://doc.gestsup.fr/
- RodrigueLoL
- Gsup LEVEL 3
- Messages : 55
- Enregistré le : mer. 28 juin 2017 11:27
- Contact :
Voilà, comme demandé
Code : Tout sélectionner
Server :
OS:LinuxSRV-INV6.1.0-40-amd64#1SMPPREEMPT_DYNAMICDebian6.1.153-1(2025-09-20)
x86_64
Apache:2.4.65(enHTTP/1.1sur192.168.1.)
MariaDB:10.11.14-MariaDB-0+deb12u2(base:bsup_ifq5872.7Mo)
PHP:8.4.14(/etc/php/8.4/fpm/php.ini)
GestSup:3.2.58(85141tickets/775utilisateurs/0équipements)
Horloge:2025-12-0117:51:44(Europe/Paris)
Fichierschargés:1526.01Mo(total7398.71Mo)
Client :
Mobile:Non
Navigateur:Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/142.0.0.0Safari/537.36
IPv4:192.168.1.
Network :
HTTPS:Ouvert(gestsup.fr:443)
Config Error :
URLserveur:Ilsemblequel'URLduserveurdéfiniedanslesparamètresgénérauxsoiterronée(http://192.168.1.)
Télémétrie:Désactivée,activerlatélémétriedansAdministration>Paramètres>Général>Serveur
PHP parameters :
file_uploads:Activé
memory_limit:512M
upload_max_filesize:50M
post_max_size:50M
max_execution_time:480s
date.timezone:Europe/Paris
PHP extensions :
php_curl:Activée
php_fileinfo:Activée
php_gd:Activée
php_iconv:Activée
php_intl:Activée
php_json:Activée
php_ldap:Activée
php_mbstring:Activée
php_openssl:Activée
php_pdo_mysql:Activée
php_xml:Activée
php_zip:Activée
Plugins :
Collectivités:1.0Kanban:1.1
Security :
HTTPS:Désactivé(lesconnexionsversleserveurnesontpaschiffrées,installeruncertificatSSLinstalleruncertificatSSL.)
VersionApache:Affichée(pourplusdesécurité,masquezlaversionapachequevousutilisez.PasserServerTokensàProddanssecurity.conf.)
VersionPHP:NonaffichéeDuréedelasession:PHP=1440sGestSup=1400m
Droitsécriture:Nonverrouillés(cf.documentation)
.Répertoireinstallation:NonprésentMotsdepasse:Aucunepolitiquedéfinie(définissezunepolitiquedemotdepassedansAdministration>Paramètres>Général>Utilisateur)
Mot de passe admin:Modifié
Logs:Activés
RestrictionIP:Désactivé(pourplusdesécurité,ilestpossiblederestreindreaccesdesclientsàcertainesadressesIP,cfAdministration>Paramètres>Général>Serveur)
.Notificationdeconnexiond'unadministrateursurunenouvelleIP:Désactivée(activercetteoptiondansAdministration>Paramètres>Général>Utilisateurs)
.Loginadmin:Actif(créerunnouvelutilisateurayantleprofiladministrateur,puisdésactiverl'utilisateurayantleloginadmin)
Listing des répertoires:Désactivé
Components :
Ace:4.0.0
makeusabrew/bootbox:6.0.2
twbs/bootstrap:4.6.2
itsjavi/bootstrap-colorpicker:3.4.0
steveathon/bootstrap-wysiwyg:2.0.1
selectize/selectize.js:0.15.2swagger-api/swagger-ui:5.11.0
FortAwesome/Font-Awesome:6.7.2
fullcalendar/fullcalendar:6.1.17
highcharts/highcharts:12.2.0
jquery/jquery:3.7.1
jeresig/jquery.hotkeys:0.2.0
thephpleague/oauth2-client:2.8.1
thephpleague/oauth2-google:4.0.1
stevenmaguire/oauth2-microsoft:2.2.0
greew/oauth2-azure-provider:2.0.0ezyang/htmlpurifier:4.18.0
microsoftgraph/msgraph-sdk-php:1.110.0
moment/moment:2.30.1
PHPMailer/PHPMailer:6.10.0
barbushin/php-imap:5.0.1
inetsys/phpgettext:1.0.12
ifsnop/mysqldump-php:2.12
FezVrasta/popper.js:1.16.0
tempusdominus/bootstrap-4:5.39.0thenetworg/oauth2-azure:2.2.2
Webklex/php-imap:6.2.0
Serveur : Debian 12 | GestSup : 3.2.59 | Apache : 2.4.65 | PHP : 8.4.14 | MariaDB : 10.11.14 | Tickets : 84 000+ | Techniciens : 5
- RodrigueLoL
- Gsup LEVEL 3
- Messages : 55
- Enregistré le : mer. 28 juin 2017 11:27
- Contact :
Suivi / résolution : "Token CSRF POST invalide"
Après analyse du code, voici ce que j'ai trouvé sur l'origine du problème, ainsi que les correctifs que j'ai mis en place (sur une instance de test, en cours de validation avant la prod). Je partage au cas où ça aide d'autres utilisateurs, et aussi pour faire remonter le point à l'équipe GestSup.
Ce qui se passe
Le jeton anti-CSRF est généré une seule fois par session :
Il est ensuite figé dans le formulaire du ticket au moment de l'affichage (champ caché "csrf_post") et n'est jamais rafraîchi côté navigateur.
Du coup, si la session PHP se termine pendant qu'un ticket reste ouvert (déconnexion automatique via le paramètre "Temps de déconnexion", ou expiration des fichiers de session côté PHP via session.gc_maxlifetime), la requête suivante repart sur une nouvelle session : un nouveau jeton est généré côté serveur, mais le formulaire renvoie encore l'ancien. La comparaison ne correspond plus, dans core/ticket.php :
Et le die() arrête la page, ce qui fait perdre toute la saisie. Ça correspond bien aux symptômes décrits : le message apparaît après quelques minutes, ou quand on laisse un ticket en attente et qu'on y revient plus tard.
Détail repéré au passage
Dans cette même vérification, strtoupper($_SERVER['REQUEST_METHOD']=='POST') applique strtoupper au résultat du test plutôt qu'à la méthode HTTP. Sans effet concret sur les requêtes POST, mais ce serait plus juste écrit strtoupper($_SERVER['REQUEST_METHOD'])=='POST' (on le retrouve aussi dans admin/users/add.php et edit.php).
Ce que j'ai fait de mon côté
1) Allonger la durée de vie des sessions pour qu'elles ne se terminent plus en pleine saisie :
- php.ini (pool FPM) : session.gc_maxlifetime = 46800 (13 h)
- GestSup > Administration > Paramètres > Général > "Temps de déconnexion" = 720 (12 h)
- Le "Temps de déconnexion" doit rester inférieur à session.gc_maxlifetime.
2) Remplacer le die() par une gestion plus souple : quand le jeton est périmé, on régénère un jeton et on réaffiche le formulaire avec la saisie conservée + un message d'information, sans enregistrer la requête refusée. La protection reste donc en place, mais l'utilisateur ne perd plus son travail.
Piste pour une version officielle
Si l'équipe GestSup le juge utile, ne plus perdre la saisie quand le jeton a expiré (et/ou rafraîchir le jeton côté navigateur) réglerait le souci à la source. Ça semble concerner plusieurs personnes sur ce fil. Merci pour le travail réalisé sur GestSup !
Après analyse du code, voici ce que j'ai trouvé sur l'origine du problème, ainsi que les correctifs que j'ai mis en place (sur une instance de test, en cours de validation avant la prod). Je partage au cas où ça aide d'autres utilisateurs, et aussi pour faire remonter le point à l'équipe GestSup.
Ce qui se passe
Le jeton anti-CSRF est généré une seule fois par session :
Code : Tout sélectionner
index.php → if(!isset($_SESSION['csrf_post'])) { $_SESSION['csrf_post'] = bin2hex(random_bytes(32)); }Du coup, si la session PHP se termine pendant qu'un ticket reste ouvert (déconnexion automatique via le paramètre "Temps de déconnexion", ou expiration des fichiers de session côté PHP via session.gc_maxlifetime), la requête suivante repart sur une nouvelle session : un nouveau jeton est généré côté serveur, mais le formulaire renvoie encore l'ancien. La comparaison ne correspond plus, dans core/ticket.php :
Code : Tout sélectionner
if(... $_POST['csrf_post'] != $_SESSION['csrf_post']) { die(DisplayMessage('error', T_('Token CSRF POST invalide'))); }Détail repéré au passage
Dans cette même vérification, strtoupper($_SERVER['REQUEST_METHOD']=='POST') applique strtoupper au résultat du test plutôt qu'à la méthode HTTP. Sans effet concret sur les requêtes POST, mais ce serait plus juste écrit strtoupper($_SERVER['REQUEST_METHOD'])=='POST' (on le retrouve aussi dans admin/users/add.php et edit.php).
Ce que j'ai fait de mon côté
1) Allonger la durée de vie des sessions pour qu'elles ne se terminent plus en pleine saisie :
- php.ini (pool FPM) : session.gc_maxlifetime = 46800 (13 h)
- GestSup > Administration > Paramètres > Général > "Temps de déconnexion" = 720 (12 h)
- Le "Temps de déconnexion" doit rester inférieur à session.gc_maxlifetime.
2) Remplacer le die() par une gestion plus souple : quand le jeton est périmé, on régénère un jeton et on réaffiche le formulaire avec la saisie conservée + un message d'information, sans enregistrer la requête refusée. La protection reste donc en place, mais l'utilisateur ne perd plus son travail.
Piste pour une version officielle
Si l'équipe GestSup le juge utile, ne plus perdre la saisie quand le jeton a expiré (et/ou rafraîchir le jeton côté navigateur) réglerait le souci à la source. Ça semble concerner plusieurs personnes sur ce fil. Merci pour le travail réalisé sur GestSup !
Serveur : Debian 12 | GestSup : 3.2.59 | Apache : 2.4.65 | PHP : 8.4.14 | MariaDB : 10.11.14 | Tickets : 84 000+ | Techniciens : 5
Bonjour,
pouvez-vous indiquer la procédure pour reproduire le problème sur la webdemo ?
Cdt
pouvez-vous indiquer la procédure pour reproduire le problème sur la webdemo ?
Cdt
GestSup: 3.2.53 | Debian: 12 | Apache: 2.4.59 | MariaDB: 11.5.2 | PHP: 8.3 | https://doc.gestsup.fr/
