临时表权限不能靠 grant select on all tables 解决,因 postgresql 临时对象在 pg_temp 命名空间,需显式授予 temp 权限;只读授权还需禁用 truncate、references、set 等隐式写操作,并防范工具侧越权与权限继承漏洞。
临时表权限为什么不能靠 grant select on all tables 解决
很多团队给分析师开库权限时,图省事直接执行 grant select on all tables in schema public to analyst_role,结果发现:临时表(create temp table 或 with 生成的隐式临时结果)照样查不了,甚至 select * from (values (1),(2)) t(a) 这种简单 cte 都报错 —— 因为 postgresql 的 select 权限不覆盖临时命名空间,而临时对象默认在 pg_temp 下创建,它压根不属于任何 schema,也不受 schema 级权限控制。
- 临时表的权限由会话级
TEMP或TEMPORARY权限决定,必须显式授予:GRANT TEMP ON DATABASE your_db TO analyst_role - 即使开了
TEMP,如果查询里用到CREATE TABLE AS或物化 CTE(如WITH data AS MATERIALIZED (...) SELECT ...),仍需额外CREATE权限(不推荐给分析师) - MySQL 和 SQL Server 没有独立的
TEMP权限概念,但临时表实际依赖CREATE TEMPORARY TABLES全局权限,且只对CREATE TEMPORARY TABLE语句生效,对子查询或派生表无影响
只读授权必须禁用哪些隐式写操作
“只读”不是加个 REVOKE INSERT, UPDATE, DELETE 就完事。分析师用的 BI 工具(比如 Metabase、Superset)或 Python 的 sqlalchemy 默认会悄悄发写命令,一旦权限漏掉一个,就可能意外改库。
- PostgreSQL 必须收回
TRUNCATE、REFERENCES(可被用于绕过行级策略)、TRIGGER,否则SELECT+REFERENCES可能触发函数侧信道泄露 - 禁止
SET类命令:分析师若能执行SET statement_timeout = '1s',可能干扰监控;更危险的是SET search_path,可切换到恶意 schema 执行同名函数 - MySQL 要关掉
FILE权限(防SELECT ... INTO OUTFILE写文件)、PROCESS(防看到其他会话 SQL)、SUPER(防绕过只读模式)
如何让临时表和只读权限真正协同生效
只读角色 + 临时表权限 ≠ 安全。常见陷阱是:分析师用 CREATE TEMP TABLE t AS SELECT ... 建好临时表后,再执行 INSERT INTO t VALUES (...) —— 这就绕过了只读限制,因为临时表本身不受只读约束。
- 解决方案不是堵死
INSERT,而是用行级安全策略(RLS)+ 策略函数强制拦截:CREATE POLICY temp_insert_block ON pg_temp.t FOR INSERT USING (false)(注意:PostgreSQL 不支持对pg_tempschema 直接建 RLS,需改用 session-level check constraint 模拟) - 更务实的做法:用视图封装常用中间逻辑,禁止直接
CREATE TEMP TABLE,改用WITH子句,并在连接池层(如 pgbouncer)或代理层(如 ProxySQL)拦截含CREATE TEMP的语句 - ClickHouse 用户注意:
CREATE TEMPORARY TABLE在 22.8+ 后默认关闭,需显式开启allow_experimental_temporary_tables = 1,且该权限无法按用户粒度控制,只能靠配置文件全局开关
权限回收时最容易被忽略的三个点
分析师离职或转岗后,删掉角色或撤回 SELECT 很容易,但以下三点常被跳过,导致残留访问能力。
-
pg_temp中的临时对象不会随会话结束自动清理干净:若分析师曾用CREATE TEMP TABLE IF NOT EXISTS创建过同名表,后续新会话可能复用旧结构,而旧权限未清,造成“幽灵访问” - 某些 BI 工具(如 Tableau)会缓存元数据并预建物化视图,这些视图可能以高权限账号运行,分析师通过查询视图间接获得越权结果
- PostgreSQL 的
INHERIT属性:如果analyst_role继承了developer_role,而后者有CREATE权限,那么即使你 revoke 了 analyst 的所有权限,只要没NOINHERIT,继承链仍有效
临时表权限和只读授权的边界,从来不在 SQL 语法层面,而在会话生命周期、工具行为和权限继承模型里——漏掉任意一层,都可能让“只读”变成纸面约定。










