【问题标题】:Oracle : check for read/write privileges, automated testingOracle:检查读/写权限,自动化测试
【发布时间】:2013-04-19 17:22:02
【问题描述】:

我有一个关于 Oracle 和检查权限的问题。

一些背景信息

我编写了一些 php 脚本来“测试”我们环境中的各种事物。其中一项任务是检查用户是否对某个过程具有执行权限以及该过程是否有效/已编译。

这里是查询

select ao.object_name, utp.grantee, ao.status, utp.privilege
from all_objects ao, user_tab_privs utp 
where utp.owner = ao.owner and
ao.object_name = utp.table_name and
upper( ao.object_name ) = :object_name and 
ao.object_type = 'PACKAGE' and
utp.privilege = 'EXECUTE' and
ao.status = 'VALID'

这很有效,并为我们节省了处理程序权限的时间;我现在确实意识到我也可以仔细检查 all_tab_privs 以检查执行访问权限。

问题

现在我的问题是,我如何对表格做类似的事情?我们遇到了一个问题,即某个用户在表上有 SELECT privs 但没有 UPDATE/INSERT privs。如何单独检查这些权限。我查看了 all_tab_privs 但没有发现它向我展示了我想要的东西。它有我可以执行的程序,但是当我检查是否存在已知表时,它不存在。例如,我将运行以下命令

select * from all_tab_privs 
where table_name = 'KNOWN_TABLE' and 
grantee = 'CURRENT_USER'
and privilege in ( 'SELECT', 'UPDATE', 'INSERT' );

但是我知道 100% 我已经可以选择/插入/更新,而不是为一个表返回 3 行,它什么也不返回。

有什么想法吗?谢谢。

免责声明

我知道我可以尝试插入/更新数据然后删除它,但我不想这样做。我宁愿不留下任何痕迹,因为这些脚本会定期运行,应该是可重复的,并且不应该改变任何数据的状态,即使它只是桌子上的一个序列。

另外,如果您可以提供一个可能的查询“列表”,我可以使用这些查询来确定权限,那很好。例如,要确定我是否有选择访问权限,请运行查询 1、2 和 3。如果其中任何一个返回数据,那么您就可以选择 privs 等进行插入/更新。

【问题讨论】:

  • 如果您将 DML 语句作为测试运行,您不打算先插入然后删除,而是先插入然后回滚。当然,它仍然会增加序列,并且您可能会遇到外键问题。
  • 您有通过角色授予的表权限吗?如果是这样,只有角色会显示为 grantee,而不是每个具有该角色的用户。
  • 不,我们不通过角色授予访问权限。无论哪种方式,如果它是由角色授予的,我不知道要查询哪个表。你能提供一个示例查询吗?
  • @AlexPoole,我想我错了。我做了检查,看起来我们正在对某些事情进行一些基于角色的访问,所以我可能需要组合查询来确定我是否有访问权限。
  • 你可以从this article by @René Nyffenegger得到这个想法。由于可以将角色授予角色,因此您需要递归地遍历它们以获取实际的对象授予。

标签: oracle oracle10g oracle11g


【解决方案1】:

这对我来说看起来相当乐观,因为角色问题可能会变得非常复杂,特别是如果角色曾经受到密码保护,而且如果没有实际尝试 DML,我永远不会真正 100% 信任该方法。

尝试以下查询可能更简单:

select count(*)
from   schema_name.table_name
where  1=0;

insert into schema_name.table_name
select *
from   schema_name.table_name
where  1=0;

delete from schema_name.table_name
where  1=0;

update schema_name.table_name
set    column_name = column_name
where  1=0;

我相信,如果没有授予权限(没有方便的数据库检查),此类查询将失败,并且他们永远不会修改任何数据。

顺便说一下,ANY 权限通常被认为是一个安全问题,因此如果授予任何用户权限,您可能希望系统失败。

【讨论】:

  • 角色问题可以复杂得多吗?正在为 Web 应用程序进行角色检查,因此我们从不对分配给 Web 应用程序的任何角色使用角色密码。
  • 我认为您的方法非常有效。我的查询也已经在递归地检查角色。我没有在“ANY TABLE”权限上抛出错误的原因是,在我们的开发环境中,我们有时会使用这些类型的权限进行快速开发和设置。
  • 对于特定的应用程序,我同意复杂性可能会受到限制,但这也意味着系统存在“隐藏约束”,因为无法使用更复杂的基于角色的结构在不修改(或破坏)此特权测试方法的情况下采用。我真的认为只有一种方法可以确定。还要考虑是否需要考虑基于列的权限 - docs.oracle.com/cd/B19306_01/network.102/b14266/… - 因为这是我们所有人都需要考虑的另一层。
  • 谢谢@David Aldridge 你说得对,更详细地检查权限是正确的,这些考虑更多的是出于一般目的而不是我的特定用例。对于我的用例,我只在表格级别进行自动化测试。在我的代码中,我将代码如下调用 $this->verifySelectPrivsOnTable( $schemaName, $tableName ) 但我绝对可以看到它被更改为 >verifySelectPrivsOnTable( $schemaName, $tableName, $columnName )
【解决方案2】:

如果您拥有通过角色授予的权限,则需要进行更复杂的检查。 cmets 中的链接提供了一些查询以查看更广泛的图片,但如果您想检查当前用户可以看到的内容 - 正如您的一个查询所建议的那样 - 那么您可以查询 session_roles 视图以查看哪些对象权限除了直接授予的对象权限外,您的会话目前还可以通过角色使用:

select atp.table_schema, atp.table_name, atp.privilege, atp.grantee,
    'Direct' as grant_type
from all_tab_privs atp
where atp.grantee = user
union all
select atp.table_schema, atp.table_name, atp.privilege, atp.grantee,
    'Via role' as grant_type
from session_roles sr
join all_tab_privs atp on atp.grantee = sr.role;

如果您想查看特定对象或特权,显然可以添加过滤器,而 grant_type 伪列仅供参考 - 并不是那么有用,因为您可以将 granteeuser 进行比较以获得和我想的一样。

您可能还想查看session_privs,以检查您的用户是否具有您期望的任何系统权限。

但是,如果您希望单个查询同时检查另一个用户或多个用户的权限,您将需要类似于链接查询的内容,以及运行它们所需的权限。

【讨论】:

    【解决方案3】:

    我最终使用基于不同查询及其返回结果的多步骤方法解决了这个问题。我正在使用一些 PHP 代码执行所有查询,所以我没有 100% 的必要只有大查询来解决所有问题。

    此外,我们的数据库在物理上是分开的,它们通过数据库链接链接在一起,所以我必须做一些额外的工作来确保这种权限检查跨数据库链接工作。

    目前我只检查 SELECT、DELETE、UPDATE 和 INSERT 权限;这就是我现在真正需要的。

    程序

    这里是一个坚果列表中的一般过程。

    1. 获取用户可用的所有数据库链接的列表。
    2. 对于以下步骤,从我们登录的当前数据库开始,然后检查从第 1 步检索到的每个数据库链接。

      2a。使用数据库查询检查表是否可见。

      2b。如果表可见,请检查是否有任何权限查询返回此用户有权访问该表。

    查询

    以下是上述每个步骤的查询。

    1 数据库链接

    select db_link from all_db_links
    

    2a 表格可见性

    select * from all_tables%DB_LINK% where table_name = :table_name and owner = :owner
    

    在适用的情况下,上面的 %DB_LINK% 将替换为 @db_link。如果我们正在检查当前连接,那么我将其完全删除。请记住,查询是由 PHP 脚本执行的,因此我可以对字符串进行一些字符串操作,以删除当前数据库的 %DB_LINK% 或将其替换为我们从步骤 1 中获得的数据库链接之一。

    2b。用户、角色、表

    这里总共有 4 个查询。

    /*****/
    /* 1 */
    /*****/
    select * 
    from user_tab_privs%DB_LINK%
    where 
    owner = :owner
    and
    table_name = :table_name
    and
    privilege = :privilege
    
    /*****/
    /* 2 */
    /*****/
    
    select * from user_sys_privs%DB_LINK% where privilege = :privilege
    
    /*****/
    /* 3 */
    /*****/
    
    select * from
          (
            select distinct granted_role from 
            (
              select null linker, granted_role 
              from user_role_privs%DB_LINK%
              union all
              select role linker, granted_role 
              from role_role_privs%DB_LINK%
            )
            start with linker is null
            connect by prior granted_role = linker 
          ) user_roles join role_tab_privs%DB_LINK% rtab on user_roles.granted_role = rtab.role
          where 
          owner = :owner
          and
          table_name = :table_name
          and
          rtab.privilege = :privilege
    
    /*****/
    /* 4 */
    /*****/
    
    select * from
      (
        select distinct granted_role from 
        (
          select null linker, granted_role 
          from user_role_privs%DB_LINK%
          union all
          select role linker, granted_role 
          from role_role_privs%DB_LINK%
        )
        start with linker is null
        connect by prior granted_role = linker 
      ) user_roles join role_sys_privs%DB_LINK% rtab on user_roles.granted_role = rtab.role
      where rtab.privilege = :privilege
    

    说明

    数据库链接

    在 phpunit 测试中,我传递了两件事:表名和模式名(所有者)。但是,由于存在数据库链接,我们必须在查询中使用 @db_link 显式检查其他数据库。否则我可能会报告一个表无法访问,而实际上它可以通过数据库链接访问。

    表格可见性

    如果用户看不到表,那么检查权限就没有意义了。检查权限还可以防止用户被授予“SELECT ANY TABLE”权限但表本身实际上并不存在导致意外失败的情况。

    4 个查询带

    如其他海报所示,用户可以通过多种方式访问​​表。具体来说,他们可以被赋予角色,这些角色可以被赋予角色,然后这些角色可以被分配访问权。或者,用户可以通过系统权限获得显式访问或通用访问。

    查询 1

    四个查询中的第一个会检查用户是否已被授予对表的显式 SELECT、DELETE 等权限。这很容易理解,理想情况下就是所有必要的

    查询 2

    第二个检查是否已授予用户任何系统权限,如删除任何表、选择任何表、插入任何表等。这些权限未在表上显式授予,但用户可以执行任何引用的操作在他们能看到的任何桌子上。

    查询 3

    第三个查询将查看用户拥有的任何角色,无论是直接还是间接,是否已被授予对表的显式 SELECT、DELETE 等权限。这类似于查询 1,只是它基于赋予用户的角色,而不是用户。

    查询 4

    第四个检查用户拥有的任何角色,无论是直接还是间接,是否已被授予任何系统权限,例如 DELETE ANY TABLE、SELECT ANY TABLE、INSERT ANY TABLE 等。这个类似于查询 2 .

    就是这样!我将这些链接在一起,并使用每个返回的结果来确定用户是否具有所需的权限。

    值得一提的细节

    如果用户拥有跨 db_link_1 的任何权限,这并不意味着他们对跨 db_link_2 访问的表拥有相同的权限。大多数人应该知道这一点,但我想确保我明确地说明了这一点。例如,跨 db_link_1 在表 1 上选择 privs 并不意味着跨 db_link_2 在表 2 上选择 privs。

    我一次检查每个 db_link。所以首先我从我直接连接的数据库开始,不需要数据库链接。然后,如果我找不到表或表上没有权限,我会转到下一个数据库链接。

    在查询 2 和 4 中,我使用 'SELECT ANY TABLE'、'DELETE ANY TABLE' 等代替 :privilege 变量。

    在查询 1 和 3 中,我使用 'SELECT'、'DELETE'、'UPDATE'、'INSERT' 代替 :privilege 变量。

    【讨论】:

    • 接受了我的“解决方案”,因为这是我现在正在使用的。但是,它是基于其他用户给出的提示和我从 oracle 文档中获得的信息。
    猜你喜欢
    • 2012-04-06
    • 1970-01-01
    • 1970-01-01
    • 2016-04-23
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多