PmaControl logo PmaControl
  • 首页
  • PmaControl
    • AI智能代理 13个本地代理
    • 定价方案 Community、Cloud、On-Premise、Premium
    • 文档 指南、API、架构
    • 客户 28+企业
    • 常见问题 25个问题 / 7个类别
    数据库
    • MariaDB 30 篇文章
    • MySQL 10 篇文章
    • Galera Cluster 6 篇文章
    • MaxScale 3 篇文章
    • ProxySQL 2 篇文章
    • Amazon Aurora MySQL 0 篇文章
    • Azure Database 0 篇文章
    • ClickHouse 0 篇文章
    • GCP CloudSQL 0 篇文章
    • Percona Server 0 篇文章
    • SingleStore 0 篇文章
    • TiDB 0 篇文章
    • Vitess 0 篇文章
    解决方案
    • 全天候支持 MariaDB & MySQL紧急支持
    • Observabilité SQL 监控、告警、拓扑
    • Haute disponibilité 复制、故障转移、Galera
    • Disaster Recovery 备份、恢复、RPO/RTO
    • Sécurité & conformité 审计、GDPR、SOC2
    • Migration & upgrade 零停机、pt-osc、gh-ost
  • 定价方案
  • 资源
    • 文档 技术指南与API
    • 常见问题 25个常见问题
    • 客户评价 客户反馈与案例
    • 博客 文章与洞察
    • 路线图 即将推出的功能
    专业领域
    • Observabilité SQL 监控、告警、Dot3拓扑
    • Haute disponibilité 复制、故障转移、Galera
    • Sécurité & conformité 审计、GDPR、SOC2、ISO 27001
    • Disaster Recovery 备份、恢复、RPO/RTO
    • Performance & optimisation Digests、EXPLAIN、调优
    • Migration & upgrade 零停机、pt-osc
    快速链接
    • GitHub Wiki 26页 — 安装、引擎、插件
    • 源代码 GitHub官方仓库
    • 全天候支持 MariaDB & MySQL紧急支持
    • 预约演示 30分钟 — 真实架构
  • 全天候支持
  • 预约演示
预约演示
🇫🇷 FR Français 🇬🇧 EN English 🇵🇱 PL Polski 🇷🇺 RU Русский 🇨🇳 ZH 中文
文档 › Protection CSRF (Origin + jeton scopé)

Protection CSRF (Origin + jeton scopé)

为什么要保护 POST 接口

若未将 CSRF 令牌绑定到会话,第三方站点可在已认证用户浏览其他网站时,向 PmaControl 提交 POST。浏览器会自动附带会话 Cookie,操作在用户毫无察觉的情况下执行——修改配置、触发任务、行内更新等。

将 GET 改为 POST 可阻止被动触发(预加载、爬虫抓取),但无法抵御从其他域发起的主动 CSRF 攻击。

共享的 Glial 助手

自 Glial v5.1.40 起,CSRF 逻辑与 Origin/Referer 校验已统一放入框架中,由所有 PmaControl 控制器共享:

  • Glial\Security\Csrf::issueToken() / Csrf::validateToken() — 按功能 scope 颁发和校验令牌。
  • Glial\Http\Request::isSameSite() — 将 Origin(优先)或 Referer(回退)与当前来源比对。
PmaControl 控制器不会重复此逻辑:Worker.php 仅包含与 POST /Worker/update 相关的 HTTP 编排。

流程示意图

CSRF 机制示意图——服务端颁发令牌、HTML 注入、AJAX 请求、四步校验链。
CSRF 机制示意图——服务端颁发令牌、HTML 注入、AJAX 请求、四步校验链。

令牌颁发

在渲染含有表单或行内可编辑单元的视图之前,控制器会颁发与功能绑定的作用域令牌:

<?php
use Glial\Security\Csrf;

$token = Csrf::issueToken($_SESSION, 'worker.update');
$this->set('csrf_token', $token);
作用域可避免为 worker.update 颁发的令牌被重放到 daemon.start。令牌存储于 $_SESSION['csrf_tokens'][$scope],直至用户会话结束。

客户端注入

对于行内可编辑单元(bootstrap-editable),令牌通过两个 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>
值会始终通过 htmlspecialchars(..., ENT_QUOTES, 'UTF-8') 进行转义,以阻止单元内任何 HTML/JS 注入。

JS App/Webroot/js/Tree/index.js 检测到 data-csrf-token 存在后,会自动将令牌追加到 bootstrap-editable 发出的 POST 参数中:

$.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;
};
AJAX 刷新(例如通过 Daemon)后,window.pmacontrolInitLineEdit(context) 会在重新加载的上下文中被再次调用,以将新令牌绑定到新的单元。

服务端校验链

在构造任何 SQL 之前,按以下顺序依次进行四项校验:

  1. HTTP 方法——仅允许 POST;其他方法直接返回 405 Method Not Allowed。
  2. 同站点来源——优先取 Origin,缺失时回退到 Referer;为 null、protocol-relative 或 scheme/host/port 不一致的请求会返回 403 Invalid request origin。
  3. CSRF 令牌——使用 hash_equals() 对比请求 payload 中的 csrf_token 字段与 $_SESSION['csrf_tokens'][$scope];缺失或不匹配时返回 403 Invalid CSRF token。
  4. Payload 白名单——仅接受该端点预期的字段与类型;任何不在白名单内的 payload 返回 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
    }
}
只要四项校验未全部通过,就不会构造任何 SQL;纵深防御在任何一道关卡被绕过时仍能生效。

参考——返回码

状态码 原因 触发条件
405 Method Not Allowed 非 POST 的 HTTP 方法。
403 Invalid request origin 跨站 Origin/Referer、Origin: null、protocol-relative URL 或 scheme/host/port 不一致。
403 Invalid CSRF token payload 中缺少令牌或与 $_SESSION['csrf_tokens'][$scope] 不匹配。
400 Invalid worker update payload 字段不在白名单内、值非整数、pk 为零或负数。
切勿为变更类端点设置 GET 兜底「方便调试」:这会悄无声息地禁用 CSRF 保护,因为该保护仅作用于 POST。

已记录的豁免情况

该 CSRF 助手仅覆盖 Web POST 接口。以下场景明确豁免:

  • CLI php glial …——无会话 Cookie,亦无 CSRF 风险面。
  • 机对机 REST API——使用独立的 API 令牌进行身份认证;这些路由禁用 Origin/Referer 校验,并在每个端点逐一记录豁免说明。
  • 只读端点——已改为 GET,不在 CSRF 防护范围内。

专属测试

CSRF 保护由 PHPUnit 测试覆盖,这些测试明确再现了历史上的攻击场景:

./vendor/bin/phpunit tests/Glial/Security/CsrfTest.php
./vendor/bin/phpunit tests/Glial/Http/RequestTest.php
./vendor/bin/phpunit tests/Controller/WorkerUpdateSecurityTest.php
若使用 Origin: https://attacker.test 或其他外部站点,即便附带有效的 CSRF 令牌,payload 也会在写入前以 403 Invalid request origin 被拒;校验链会在 Origin 检查阶段就拦截请求,根本不会进入令牌校验。
本页目录
  • 为什么要保护 POST 接口
  • 共享的 Glial 助手
  • 流程示意图
  • 令牌颁发
  • 客户端注入
  • 服务端校验链
  • 参考——返回码
  • 已记录的豁免情况
  • 专属测试
← 上一页 下一页 →
PmaControl
+33 6 63 28 27 47 contact@pmacontrol.com
法律声明 GitHub 联系我们
不要等到故障发生才了解您的架构。 © 2014-2026 PmaControl — 68Koncept