PAYATHON 2026

MySQL 视图在 JOIN 条件中调用自定义函数为何报权限错误?

数据小许

结论

根据 MySQL 文档的权限模型,如果视图实际使用 SQL SECURITY DEFINER,且定义者拥有所需权限,那么仅将 f() 从 WHERE 移到内连接的 ON 条件,不应导致查询视图的 joe 需要额外的函数 EXECUTE 权限。MySQL 8.0 CREATE VIEW 文档

出现这种情况值得排查。不过,现有材料缺少函数定义、实际视图定义和完整授权信息,还不能确认是 MySQL 缺陷、Aurora 特有问题,还是具体版本中已经修复的问题。报错本身也不足以证明存在权限提升漏洞。

视图权限与函数权限如何衔接

这里的“继承权限”,更准确地说是执行时使用指定账户的安全上下文。joe 不会因此获得直接调用 f() 的授权。

权限检查分为两个环节:

  • 查询视图:joe 需要视图的 SELECT 权限。视图使用 SQL SECURITY DEFINER 时,访问底层对象所需的权限按视图定义者检查,包括调用存储函数所需的权限。
  • 执行函数体:使用谁的权限由函数自身的 SQL SECURITY 决定。函数使用 DEFINER 时,函数体按函数定义者的权限执行;使用 INVOKER 时,在正常的权限链中,调用上下文由外层视图的安全设置决定。

函数自身的 SQL SECURITY DEFINER 不会取消调用函数时的 EXECUTE 权限检查。这些规则见 CREATE VIEW 和 CREATE FUNCTION 文档。

先核对实际定义和授权

请有权查看定义的管理账户执行:

SHOW CREATE VIEW db.v;
SHOW CREATE FUNCTION db.f;
SHOW GRANTS FOR 'joe'@'%';

重点检查:

  1. 视图保存的 DEFINER 是哪个完整账户,包括用户名和主机部分。
  2. 视图是否确实使用 SQL SECURITY DEFINER。
  3. 视图定义者是否具有读取底层表所需的权限,以及 db.f 的 EXECUTE 权限。
  4. 函数自身的 DEFINER、SQL SECURITY,以及函数体是否还涉及其他对象或例程。

原示例没有显式写出 DEFINER 和 SQL SECURITY。MySQL 默认以创建视图的账户为定义者,安全模式默认为 DEFINER;仍应以 SHOW CREATE VIEW 返回的实际定义为准。存储对象访问控制文档

再用 joe 的连接执行以下语句,确认实际匹配的账户并复现问题:

SELECT USER(), CURRENT_USER();
SELECT * FROM db.v;

如果确实是视图定义者缺少 EXECUTE,应向该定义者补齐权限。直接给 joe 授权可能掩盖问题,还会允许它在视图之外调用函数,与原来的权限隔离目标不同。

可以暂时采用 WHERE 写法吗?

对于题目中的内连接,可以把谓词放到 WHERE,作为临时规避方式。这种写法已在该环境中观察到有效。下面的语句显式指定了安全模式,应由预期的视图定义者执行,并在替换后核对 DEFINER:

CREATE OR REPLACE
SQL SECURITY DEFINER
VIEW db.v AS
SELECT a.*
FROM db.a AS a
CROSS JOIN db.b AS b
WHERE b.x = db.f();

GRANT SELECT ON db.v TO 'joe'@'%';

这里的 CROSS JOIN ... WHERE 明确表达了原示例的内连接筛选关系,没有增加 a 与 b 之间的其他关联条件。如果多条 b 记录满足条件,同一条 a 记录仍可能重复出现。

这一改写不能直接用于 LEFT JOIN 或 RIGHT JOIN。将外连接的 ON 条件移到 WHERE,可能过滤掉本应保留的未匹配行。连接规则可参考 MySQL JOIN 文档。另外,若 f() 有副作用或结果随调用变化,还需要单独验证结果与调用行为,不能据此保证两种写法具有相同的调用次数。

如何确认是否为实现缺陷

在权限和定义完全一致的测试环境中,保留两个不同名称的视图,仅改变谓词位置,再由同一个 joe 连接分别查询。复现材料应包含表结构、函数完整定义、视图定义、相关授权、完整查询和错误信息。

同时记录 Aurora 的具体引擎版本,不要只记录 MySQL 兼容版本。若相同最小用例在原生 MySQL 上也能复现,可向 MySQL 提交缺陷;若只在 Aurora 上复现,则向 AWS Support 提供材料。没有对应的缺陷记录或验证结果前,不宜把原因归结为某个优化器行为,也不能承诺升级即可解决。

备注:内容仅供参考。