oracle 23c中创建只读开发者账号不能使用select any table,必须通过pdb内对象级授权+同义词+显式连接路径实现,否则违反最小权限原则或导致ora-00942错误。

直接给结论:Oracle 23c 中创建只读开发者账号,**不能靠 SELECT ANY TABLE 这类高危系统权限**,必须走对象级授权 + 同义词 + 显式连接路径的组合方案。否则要么权限过大(违反最小权限原则),要么查不到表(缺同义词或 schema 前缀)。
为什么 SELECT ANY TABLE 在 23c 里不推荐用
Oracle 23c 默认启用 COMMON_USER_PREFIX 和 CDB/PDB 隔离策略,SELECT ANY TABLE 会跨 PDB 暴露所有可访问表(包括数据字典、其他租户表),且无法限制到指定 schema。实测中,授予该权限后,用户能执行 SELECT * FROM sys.user_tables,这在审计和等保场景下是明确违规项。
常见错误现象:ORA-01031: insufficient privileges(没给 CREATE SESSION)或 ORA-00942: table or view does not exist(给了 SELECT ANY TABLE 却没连对 PDB,或对象在另一个 PDB)。
建议做法:
- 始终在目标 PDB 内以
sys as sysdba或具有PDB_DBA角色的用户操作 - 避免在 CDB$ROOT 中创建用户;新账号必须带
CONTAINER=CURRENT - 不使用
SELECT ANY TABLE,改用动态生成的GRANT SELECT ON schema.table TO user
创建账号并授基本连接权限(PDB 级)
关键点:必须显式指定 CONTAINER=CURRENT,否则账号会建在 CDB$ROOT,后续无法访问 PDB 内对象。
示例(在目标 PDB 中执行):
CREATE USER dev_ro IDENTIFIED BY "DevR0#2026" DEFAULT TABLESPACE users CONTAINER=CURRENT; GRANT CREATE SESSION TO dev_ro CONTAINER=CURRENT; GRANT CREATE VIEW TO dev_ro CONTAINER=CURRENT; GRANT CREATE SYNONYM TO dev_ro CONTAINER=CURRENT;
注意:
- 密码含特殊字符必须用双引号包裹,否则报
ORA-00922 -
CREATE SYNONYM权限必须给,否则后续无法隐藏 schema 名 - 不要给
UNLIMITED TABLESPACE,应指定具体表空间并配 quota
批量授予指定 schema 下所有表的 SELECT 权限
假设源 schema 是 app_prod,且你已在该 schema 所属 PDB 中登录(如用 app_prod 用户或 sys as sysdba 切入):
运行以下查询生成授权语句:
SELECT 'GRANT SELECT ON app_prod.' || object_name || ' TO dev_ro;' FROM dba_objects WHERE owner = 'APP_PROD' AND object_type = 'TABLE' AND status = 'VALID';
复制结果并执行(注意:必须在 PDB 内执行,且 dev_ro 用户已存在)。
容易踩的坑:
- 大小写敏感:
owner值需全大写(除非原 schema 创建时用了双引号) - 忽略
status = 'VALID'会导致对无效对象授权,报ORA-04043 - 视图、物化视图、序列等若也需要只读访问,把
object_type改成IN ('TABLE','VIEW','MATERIALIZED VIEW','SEQUENCE')
为开发者账号创建同义词(省去 schema 前缀)
否则开发者每次都要写 SELECT * FROM app_prod.orders,体验差且易出错。
在 dev_ro 账号下执行(或用 DBA 账号代执行):
SELECT 'CREATE OR REPLACE SYNONYM ' || object_name || ' FOR app_prod.' || object_name || ';' FROM dba_objects WHERE owner = 'APP_PROD' AND object_type = 'TABLE' AND status = 'VALID';
执行生成的语句后,dev_ro 就可以直接 SELECT * FROM orders。
重要提醒:
- 同义词名不能与保留字冲突(如
order不行,但orders可以) - 如果源 schema 有同名对象(比如两个表都叫
log但不同前缀),同义词会覆盖,需手动重命名 - 23c 中同义词默认作用域是当前 PDB,无需额外指定
CONTAINER
真正麻烦的不是授权本身,而是后续维护:当 app_prod 新增表时,必须重新跑一遍授权 + 同义词脚本;如果用角色封装权限,23c 的 PDB 级角色仍需每个 PDB 单独赋权——这些细节没人提,但线上出过三次故障。











