Oracle无内置安全只读角色,需自建app_ro_role并显式授予CREATE SESSION及目标表/物化视图的SELECT权限,禁用ANY权限与CONNECT角色,验证须通过查询、DML报错及数据字典不可访问三步确认。
Oracle没有内置只读角色,必须自定义
oracle 官方不提供语义明确、权限收敛的 read_only_role。像 select_catalog_role 看似合理,但它隐含对 dba_*、v$ 等数据字典视图的 select 权限,实际允许用户发现数据库结构、会话、锁等敏感信息,远超“只读业务数据”范畴。真正可控的做法是:自己建角色、只授 create session 和显式 select 权限。
创建角色 + 授予最小必要权限的完整流程
角色本身不带登录能力,必须显式授予 CREATE SESSION;所有表级 SELECT 必须手动或动态授予,不能依赖通配符或 ANY 权限。
- 先执行:
CREATE ROLE app_ro_role; - 再授基础会话权:
GRANT CREATE SESSION TO app_ro_role; - 仅对目标 schema 的常规表授 SELECT:
SELECT 'GRANT SELECT ON ' || owner || '.' || table_name || ' TO app_ro_role;' FROM dba_tables WHERE owner = 'APP_SCHEMA' AND temporary = 'N'; - 物化视图需单独处理:
SELECT 'GRANT SELECT ON ' || owner || '.' || mview_name || ' TO app_ro_role;' FROM dba_mviews WHERE owner = 'APP_SCHEMA'; - 跳过
SYNONYM授权——同义词只是别名,只要底层对象已授权且用户能解析它(即有SELECT),就可直接用synonym_name查询
把角色赋给用户时的关键限制点
角色生效的前提是用户具备解析对象的权限,而 Oracle 默认不自动赋予 SELECT 权限的“可见性”。常见翻车点不是角色没建好,而是用户缺 CREATE SESSION 或被锁住。
- 用户必须已存在,且未被
ACCOUNT LOCK(否则角色无意义) - 务必单独执行:
GRANT app_ro_role TO app_ro_user;,不要混在CREATE USER语句里 - 避免同时授
CONNECT角色——它在旧版本中可能附带UNLIMITED TABLESPACE,与只读目标冲突 - 若用户需跨 PDB 访问,角色必须在对应 PDB 内创建并授权,CDB 级角色不会自动下放
验证只读是否真正生效的三步检查法
光看 GRANT 语句执行成功不代表权限到位。真实权限链受对象所有权、同义词解析、视图定义权限等多层影响。
- 用该用户连接后,执行:
SELECT COUNT(*) FROM app_schema.orders;→ 应返回结果 - 执行:
INSERT INTO app_schema.orders VALUES (999, 'test');→ 必须报ORA-01031: insufficient privileges - 执行:
SELECT * FROM v$session;或SELECT * FROM dba_tables;→ 应报ORA-00942: table or view does not exist(而非权限不足),说明没意外拿到数据字典访问权
最容易被忽略的是物化视图和临时表——DBA_TABLES 不包含它们,但业务 SQL 可能直接查 schema.mv_name,漏授就会导致“部分表查不到”。


















