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'@'%';
重点检查:
- 视图保存的
DEFINER是哪个完整账户,包括用户名和主机部分。 - 视图是否确实使用
SQL SECURITY DEFINER。 - 视图定义者是否具有读取底层表所需的权限,以及
db.f的EXECUTE权限。 - 函数自身的
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 提供材料。没有对应的缺陷记录或验证结果前,不宜把原因归结为某个优化器行为,也不能承诺升级即可解决。
备注:内容仅供参考。
