首页 文章

试图限制对Oracle DB的访问以运行查询 - 设计建议

提问于
浏览
1

我正在开发一个oracle DB的web界面,其中: -

  • 用户可以要求访问特定模式

  • 如果他被授予访问权限,他应该能够仅在该模式上运行查询 . (所有其他查询,如其他模式,sys表,all_tables,dual应该被拒绝)

我创建了一个只读用户,可以访问该DB中的任何表(NOT SYS) .

现在,我面临的问题是: - 1.如果该DB有两个模式schema1和schema2,并且用户可以根据元数据访问schema1,并且如果他尝试运行schema2.table,它将运行,因为read_only用户具有any_table权限 . 他可以在all_tables上运行查询(这不是空闲的)

这可以通过以下任一方法解决: - 方法1:为每个模式创建用户并向该用户授予schema.table *特权 . 问题: - 1.如果有100个模式,将有100个这样的用户 . 2.如果模式中有新表,则需要为新表授予显式权限 .

方法2:我正在考虑使用Regex方法来解析用户提供的查询,并且如果他被批准为schema1,则只允许schema1.table . 如果他试图运行schema2.table它将失败 .

问题: - 可能有许多极端情况,如子查询,连接等 .

有没有更好的方法来解决这个问题 .

2 回答

  • 1

    忘记解析,几乎不可能准确地解析Oracle SQL . 而是使用 EXPLAIN PLAN 填充的 PLAN_TABLE 来查找依赖项 .

    • 为每个语句生成唯一ID .

    • 通过运行 explain plan set statement_id = 'UNIQUE_ID' for $$SELECT_STATEMENT$$ 为每个语句生成执行计划 .

    • 查询 PLAN_TABLE 以查找查询引用的模式 .

    基于一些快速测试,这似乎适用于表,系统表,DUAL,同义词和视图 .

    它至少在这些情况下不起作用 .

    • 优化器转换,完全从计划中删除表 . 例如,下面的查询引用了TABLE3,尽管它没有出现在执行计划中,因为它没有被使用 . 这些是罕见的情况,可能不是一个真正的问题 .
    select *
    from table1
    where exists (select (select count(*) from table3) from table2);
    
    • 程序代码(如函数和类型)不会显示在执行计划中 . 保护自定义过程代码可能需要不同的方法 . 例如,可能需要使用游标中的SELECT语句动态创建临时过程,然后以递归方式检查 DBA_DEPENDENCIES .

    Examples

    创建示例模式 .

    create table table1(a number);
    create table table2(a number primary key);
    

    此查询仅使用本地表,因此仅返回一个用户 .

    explain plan set statement_id = '1' for
    select *
    from table1
    join table2
        on table1.a = table2.a;
    
    select distinct object_owner
    from plan_table
    where statement_id = '1'
        and object_owner is not null;
    
    OBJECT_OWNER
    ------------
    JHELLER
    

    此查询引用系统表并返回SYS模式,并且验证失败 .

    explain plan set statement_id = '2' for
    select (select count(*) from all_objects)
    from table1
    join table2
        on table1.a = table2.a;
    
    select distinct object_owner
    from plan_table
    where statement_id = '2'
        and object_owner is not null;
    
    OBJECT_OWNER
    ------------
    JHELLER
    SYS
    

    此查询使用DUAL并且应该验证失败 . 检测DUAL有点棘手,因为它不是真正的表 .

    explain plan set statement_id = '3' for
    select (select count(*) from dual)
    from table1
    join table2
        on table1.a = table2.a;
    
    select distinct object_owner
    from plan_table
    where statement_id = '3'
        and object_owner is not null
    union all
    select distinct 'SYS'
    from plan_table
    where statement_id = '3'
        and operation = 'FAST DUAL';
    
    OBJECT_OWNER
    ------------
    JHELLER
    SYS
    

    Disclaimer

    在大多数情况下,我不建议使用此解决方案 . 我同意贾斯汀对这一要求的担忧 . 如果它遵循标准的Oracle安全方法,那么管理数百个模式和对象可能会更简单 . 并且最好不要迟早地打击不合理的“安全”请求 . 不幸的是,在实践中,这些战斗通常会丢失 .

  • 1

    您似乎正在描述一个普通的客户端 - 服务器方案 .

    如果最终用户是您描述的数据库模式,那么您应该实现数据库“角色” . 分配对象访问数据库“角色”,然后根据您的安全定义将这些“角色”分配给最终用户 .

    http://docs.oracle.com/database/121/SQLRF/statements_6014.htm

    要避免使用“schema1.table”和“schema2.table”,您可以实现数据库同义词 .

    https://docs.oracle.com/database/121/SQLRF/statements_7001.htm

    使用“角色”“同义词”,您将拥有足够的控制(安全性)和易于管理 .

    这里有一些Oracle安全准则:

    http://docs.oracle.com/cd/B28359_01/network.111/b28531/guidelines.htm#DBSEG009

    http://www.oracle.com/technetwork/articles/entarch/arch-approach-inf-sec-360705.pdf

相关问题