PmaControl logo PmaControl
  • Accueil
  • PmaControl
    • Agents IA 13 agents on-premise
    • Nos offres Community, Cloud, On-Premise, Premium
    • Documentation Guides, API, architecture
    • Clients 28+ entreprises
    • FAQ 25 questions / 7 catégories
    Bases de données
    • MariaDB 30 articles
    • MySQL 10 articles
    • Galera Cluster 6 articles
    • MaxScale 3 articles
    • ProxySQL 2 articles
    • Amazon Aurora MySQL 0 article
    • Azure Database 0 article
    • ClickHouse 0 article
    • GCP CloudSQL 0 article
    • Percona Server 0 article
    • SingleStore 0 article
    • TiDB 0 article
    • Vitess 0 article
    Solutions
    • Support 24×7 Urgences MariaDB & MySQL
    • Observabilité SQL Monitoring, alertes, topologie
    • Haute disponibilité Réplication, failover, Galera
    • Disaster Recovery Backup, restore, RPO/RTO
    • Sécurité & conformité Audit, RGPD, SOC2
    • Migration & upgrade Zero downtime, pt-osc, gh-ost
  • Nos offres
  • Ressources
    • Documentation Guides techniques & API
    • FAQ 25 questions fréquentes
    • Témoignages Retours clients & cas d'usage
    • Blog Articles & insights
    • Roadmap Fonctionnalités à venir
    Domaines d'expertise
    • Observabilité SQL Monitoring, alertes, topologie Dot3
    • Haute disponibilité Réplication, failover, Galera
    • Sécurité & conformité Audit, RGPD, SOC2, ISO 27001
    • Disaster Recovery Backup, restore, RPO/RTO
    • Performance & optimisation Digests, EXPLAIN, tuning
    • Migration & upgrade Zero downtime, pt-osc
    Liens rapides
    • Wiki GitHub 26 pages — install, engine, plugins
    • Code source Repository GitHub officiel
    • Support 24×7 Urgences MariaDB & MySQL
    • Réserver une démo 30 min — architecture réelle
  • Support 24×7
  • Réserver une démo
Réserver une démo
🇫🇷 FR Français 🇬🇧 EN English 🇵🇱 PL Polski 🇷🇺 RU Русский 🇨🇳 ZH 中文
Documentation › Protection CSRF (Origin + jeton scopé)

Protection CSRF (Origin + jeton scopé)

Pourquoi protéger les POST

Sans jeton CSRF lié à la session, un site tiers peut soumettre un formulaire POST vers PmaControl pendant qu'un utilisateur authentifié navigue ailleurs. Le navigateur joint automatiquement les cookies de session et l'action s'exécute hors intention utilisateur — modification de configuration, lancement d'opération, mise à jour inline.

Le passage de GET à POST corrige les déclenchements passifs (preload, lien crawlé), mais il ne suffit pas contre une attaque CSRF active depuis un autre domaine.

Helper mutualisé Glial

À partir de Glial v5.1.40, la logique CSRF et la validation Origin/Referer sont mutualisées dans le framework, donc partagées par tous les contrôleurs PmaControl :

  • Glial\Security\Csrf::issueToken() / Csrf::validateToken() — émission et validation d'un jeton par scope fonctionnel.
  • Glial\Http\Request::isSameSite() — comparaison Origin (priorité) puis Referer (fallback) contre l'origine courante.
Aucun contrôleur PmaControl ne duplique cette logique : Worker.php contient uniquement l'orchestration HTTP propre à POST /Worker/update.

Schéma du flux

Schéma du mécanisme CSRF — émission du jeton côté serveur, injection HTML, requête AJAX, chaîne de validation à 4 étapes.
Schéma du mécanisme CSRF — émission du jeton côté serveur, injection HTML, requête AJAX, chaîne de validation à 4 étapes.

Émission du jeton

Avant de rendre une vue contenant un formulaire ou une cellule inline-editable, le contrôleur émet un jeton scopé par fonctionnalité :

<?php
use Glial\Security\Csrf;

$token = Csrf::issueToken($_SESSION, 'worker.update');
$this->set('csrf_token', $token);
Le scope évite qu'un jeton émis pour worker.update soit rejouable sur daemon.start. Le jeton est stocké dans $_SESSION['csrf_tokens'][$scope] et persiste jusqu'à la fin de la session utilisateur.

Injection côté client

Pour les cellules inline-editable (bootstrap-editable), le jeton est injecté via deux attributs data-* :

<td class="editable"
    data-name="nb_worker"
    data-csrf-field="csrf_token"
    data-csrf-token="<?= htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8') ?>">
    5
</td>
Les valeurs sont systématiquement échappées via htmlspecialchars(..., ENT_QUOTES, 'UTF-8') pour neutraliser toute injection HTML/JS dans la cellule.

Le JS App/Webroot/js/Tree/index.js détecte la présence de data-csrf-token et ajoute automatiquement le jeton aux paramètres POST envoyés par bootstrap-editable :

$.fn.editable.defaults.params = function (params) {
    var $cell = $(this).closest('[data-csrf-token]');
    if ($cell.length) {
        params[$cell.data('csrf-field')] = $cell.data('csrf-token');
    }
    return params;
};
Après un rafraîchissement AJAX (par exemple via le Daemon), window.pmacontrolInitLineEdit(context) est rappelé sur le contexte rechargé pour relier le nouveau jeton aux nouvelles cellules.

Chaîne de validation côté serveur

Quatre contrôles s'enchaînent dans cet ordre exact, en amont de toute construction SQL :

  1. Méthode HTTP — uniquement POST ; toute autre méthode renvoie 405 Method Not Allowed.
  2. Origine same-site — Origin en priorité, puis Referer en fallback ; les valeurs null, protocol-relatives ou avec scheme/host/port différent sont rejetées avec 403 Invalid request origin.
  3. Jeton CSRF — comparaison hash_equals() entre le champ csrf_token du payload et $_SESSION['csrf_tokens'][$scope] ; un jeton manquant ou invalide retourne 403 Invalid CSRF token.
  4. Allowlist payload — uniquement les champs et types prévus pour cet endpoint ; un payload hors liste retourne 400 Invalid worker update payload.
<?php
class Worker
{
    public function update()
    {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(405);
            return;
        }
        if (!Glial\Http\Request::isSameSite($_SERVER)) {
            http_response_code(403);
            echo 'Invalid request origin';
            return;
        }
        if (!Glial\Security\Csrf::validateToken($_POST, $_SESSION, 'worker.update')) {
            http_response_code(403);
            echo 'Invalid CSRF token';
            return;
        }

        $sql = $this->buildWorkerUpdateSql($_POST);
        if ($sql === null) {
            http_response_code(400);
            echo 'Invalid worker update payload';
            return;
        }

        // SQL exécuté ici uniquement
    }
}
Tant que les quatre contrôles n'ont pas tous passé, aucune requête SQL n'est construite : la défense en profondeur tient même si l'un des verrous saute.

Référence — codes de retour

Code Cause Quand
405 Method Not Allowed Méthode HTTP autre que POST.
403 Invalid request origin Origin/Referer hors site, Origin: null, protocol-relative ou scheme/host/port différent.
403 Invalid CSRF token Jeton absent du payload ou ne correspondant pas à $_SESSION['csrf_tokens'][$scope].
400 Invalid worker update payload Champ hors allowlist, valeur non entière, pk négatif ou nul.
Ne donnez jamais à un endpoint mutatif un fallback en GET « pour debug » : cela désactiverait silencieusement la protection CSRF, qui ne s'applique qu'au POST.

Exemptions documentées

Le helper CSRF couvre uniquement les POST web. Les surfaces suivantes sont explicitement exemptées :

  • CLI php glial … — pas de cookie de session, pas de surface CSRF.
  • API REST machine-to-machine — authentification par jeton API séparé ; le contrôle Origin/Referer est désactivé pour ces routes et l'exemption est documentée par endpoint.
  • Endpoints read-only — convertis en GET, donc hors du périmètre CSRF.

Tests dédiés

La protection CSRF est couverte par des tests PHPUnit qui matérialisent explicitement le scénario d'attaque historique :

./vendor/bin/phpunit tests/Glial/Security/CsrfTest.php
./vendor/bin/phpunit tests/Glial/Http/RequestTest.php
./vendor/bin/phpunit tests/Controller/WorkerUpdateSecurityTest.php
Avec Origin: https://attacker.test ou un autre site externe, le payload est rejeté en 403 Invalid request origin avant toute écriture, même si un jeton CSRF valide est fourni — la chaîne de validation refuse la requête sur le contrôle Origin avant d'arriver au jeton.
Sur cette page
  • Pourquoi protéger les POST
  • Helper mutualisé Glial
  • Schéma du flux
  • Émission du jeton
  • Injection côté client
  • Chaîne de validation côté serveur
  • Référence — codes de retour
  • Exemptions documentées
  • Tests dédiés
← Page précédente Page suivante →
PmaControl
+33 6 63 28 27 47 contact@pmacontrol.com
Mentions légales GitHub Contact
N'attendez pas l'incident pour comprendre votre architecture. © 2014-2026 PmaControl — 68Koncept