oracle中实现只读用户必须显式撤销create table和create index等系统权限,仅授select any table不足够;需revoke resource角色并检查public及中间角色的隐式授权,最后验证session_privs确保无残留。

直接禁用 CREATE TABLE 和 CREATE INDEX 权限即可
Oracle 没有“只读用户”这种内置角色,所谓只读,必须显式收回写入类权限。只要用户拥有 CREATE TABLE 或 CREATE INDEX,就能在自己默认表空间里建对象——哪怕只给了 SELECT ANY TABLE,也不影响建表建索引。
撤销系统权限是唯一可靠方式
不能靠角色继承或 profile 限制建表建索引,必须用 REVOKE 显式移除对应系统权限:
REVOKE CREATE TABLE FROM username;REVOKE CREATE INDEX FROM username;- 如果用户还持有
RESOURCE角色,务必先REVOKE RESOURCE FROM username;—— 因为该角色默认包含CREATE TABLE、CREATE SEQUENCE等多项权限 - 检查是否残留其他高危权限:
SELECT privilege FROM dba_sys_privs WHERE grantee = 'USERNAME';
常见误操作:只给 SELECT 权限但忘了 revoke
很多人以为授予 SELECT ANY TABLE + CREATE SESSION 就够安全,结果用户仍能建表,原因包括:
- 用户被无意中授予过
RESOURCE或DBA角色 - 之前执行过
GRANT CREATE TABLE TO PUBLIC;(极危险,应立即查并撤回) - 用户是通过中间角色获得权限的,比如
GRANT select_role TO username;,而select_role里混入了CREATE TABLE - 使用
ALTER USER username DEFAULT ROLE ALL;会激活所有已授角色,包括含建表权限的角色
验证权限是否真正清除
执行后务必验证,避免残留:
- 登录该用户,尝试
CREATE TABLE t(x INT);—— 应报ORA-01031: insufficient privileges - 查当前用户实际持有的系统权限:
SELECT * FROM session_privs; - 查其被授予的所有权限(含通过角色继承的):
SELECT * FROM dba_role_privs WHERE grantee = 'USERNAME';和SELECT * FROM role_sys_privs WHERE role IN (SELECT granted_role FROM dba_role_privs WHERE grantee = 'USERNAME');
权限撤销不生效往往不是语法问题,而是没清理干净间接授予路径。尤其注意 RESOURCE 角色和 PUBLIC 授予这类高危权限的隐蔽入口。











