2

我有一个关于 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' );

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

有任何想法吗?谢谢你。

免责声明

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

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

4

3 回答 3

6

这对我来说看起来相当乐观,因为角色问题可能会变得非常复杂,特别是如果角色得到密码保护,而且如果没有实际尝试 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 权限通常被认为是一个安全问题,因此如果授予任何用户权限,您可能希望系统失败。

于 2013-05-28T16:39:00.627 回答
4

如果您具有通过角色授予的权限,则需要进行更复杂的检查。评论中的链接提供了一些查询以查看更广泛的图片,但如果您想检查当前用户可以看到的内容 - 正如您的一个查询所建议的那样 - 那么您可以查询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,以检查您的用户是否具有您期望的任何系统权限。

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

于 2013-04-22T16:15:47.880 回答
1

我最终使用基于不同查询及其返回结果的多步骤方法解决了这个问题。我正在使用一些 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

第二个检查是否已授予用户任何系统权限,如 DELETE ANY TABLE、SELECT ANY TABLE、INSERT ANY TABLE 等。这些权限并未在表上显式授予,但用户可以在任何表上执行任何引用的操作他们有知名度。

查询 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 上选择权限并不意味着通过 db_link_2 在表 2 上选择权限。

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

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

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

于 2013-05-28T15:47:13.587 回答