【问题标题】:How do I hide my Oracle table?如何隐藏我的 Oracle 表?
【发布时间】:2011-11-26 02:20:14
【问题描述】:

这是场景(简化示例):

我有一个名为 ABC 的 Oracle 用户/模式。 ABC 拥有一个名为 TRN 的表。客户端代码作为 ABC 连接到数据库并从 ABC.TRN 中选择。

到目前为止一切顺利。但是,我不希望客户端代码指定 Oracle 模式名称。现在我想我已经删除了客户端代码中所有引用模式的引用,但我想对此进行测试以确保。

所以我想创建一个名为 DEF 的新用户/模式,客户端将使用它来连接到数据库。当客户端应用程序从 ABC.TRN 中选择时,它必须给出错误。但是,如果客户端应用程序从 TRN(无模式名称)中选择,它必须返回数据。

有没有办法做到这一点?注意DEF必须和ABC在同一个数据库,只有一个表TRN表(ABC所有),不能使用数据库链接。

我尝试使用指向 ABC.TRN 的同义词创建一个新的 XYZ 用户,并赋予它在 ABC.TRN 上的选择权限。然后,我使用指向 XYZ.TRN 的同义词创建了 DEF 用户,并赋予 DEF 对 XYZ.TRN 的选择权限。这可行,但 Oracle 足够聪明,知道如果 DEF 有权从 XYZ.TRN 中进行选择,那么它也有权从 ABC.TRN 中进行选择,从而违背了本练习的目的,因为我希望这个案例给出错误。

交给你...

【问题讨论】:

    标签: database oracle schema synonym rights


    【解决方案1】:

    没有简单的方法可以做到这一点。

    一种方法是政治性的:进行代码审查,可能会自动搜索代码库,当人们这样做时,只需拍打手腕。

    架构方法类似于您的三模式结构,但有一个微妙的转折:中间的模式使用视图。因此,模式 ABC 拥有表并将它们的权限授予模式 XYZ。模式 XYZ 针对这些表构建简单视图(SELECT *,无 WHERE 子句)并将视图的权限授予模式 DEF。 Schema DEF 只能从 XYZ 对象中选择。

    当然,所有这些努力仍然不会阻止开发人员编写SELECT * FROM xyz.whatever。在这种情况下,我建议您参考我的第一个建议 8-)


    实际上有一种非常邪恶的方法可以做到这一点。在面向应用的架构 (DEF) 中使用同义词,然后更改数据拥有架构 (ABC) 的名称

    当然,只有在您的安装脚本完全参数化且没有自己的硬编码架构名称时,您才应该尝试这种策略。

    【讨论】:

    • 这正是我所做的,进行代码审查、自动源代码扫描和教育开发人员。但我想绝对确定在 FAT 阶段。它可以通过带有 fromuser= touser= 子句的 exp/imp(或 expdp/impdp)来完成。我试图避免这种情况,但这似乎是唯一的方法......
    • +1,用于视图和同义词。我的公司也制定了同样的做法,而且效果很好。这仅在您撤销公共选择时才可执行,因此开发人员无法编写select * from xyz.blahuser_privileges 上的一项简单工作将摆脱它们。任何不符合标准的代码都不起作用。
    • @VinceJS,为什么要导出/导入?改变表...重命名
    • 是的,可以使用alter table rename,但如果有多个,它会变得有点乏味。我打算重命名模式以隐藏它,但 Oracle 不允许这样做,所以唯一的方法是使用 fromuser= touser= 子句 exp/imp(或 expdp/impdp)(并进行一些修复,因为 imp如果远非完美!)
    【解决方案2】:

    你真的需要抛出错误吗?还是您只需要验证应用程序没有使用完全限定名称(即ABC.TRN)?

    假设您只是想验证应用程序没有使用完全限定名称,并且抛出错误只是您想通知您的机制,您可能可以通过查询 V$SQL 来验证代码,而应用程序正在运行。 V$SQL 列出了 Oracle 共享池中的所有 SQL 语句。如果您在应用程序运行时定期查询该表,您将看到它发出的所有 SQL 语句。然后,您可以记录任何使用完全限定名称的语句。

    例如

    CREATE OR PROCEDURE look_for_abc_trn
    AS
    BEGIN
      FOR x IN (SELECT *
                  FROM v$sql
                 WHERE upper(sql_fulltext) LIKE '%ABC.TRN%')
      LOOP
        INSERT INTO log_of_bad_sql( sql_fulltext, <<other columns>> )
          VALUES( x.sql_fulltext, <<other columns>> );
      END LOOP;
    END;
    

    如果您在应用程序运行时每隔几分钟运行一次该过程,您将看到任何使用完全限定名称的 SQL,并将该语句记录在 LOG_OF_BAD_SQL 表中。对于编写良好的系统来说,每隔几分钟可能就有点过分了,您只需要确保它的运行频率高于共享池中语句的老化频率。如果您的应用程序未正确使用绑定变量,则可能需要每隔几分钟进行一次,以免遗漏任何内容。

    【讨论】:

    • 这是检查应用程序未使用完全限定名称的好方法,谢谢!
    【解决方案3】:

    ALTER SESSION 怎么样?

             ALTER SESSION SET CURRENT_SCHEMA = schema
    

    这将允许您以用户身份登录,该用户已被授予对模式 X 拥有的表的选择权限,并执行将会话更改为模式 X 的 SP。前端代码不会知道这已经发生了。

    但是,如果您的前端代码指定了架构 X:

               select * from X.tableName
    

    我认为它不会引发错误。

    也许您可以解释为什么客户端代码在使用正确的当前架构名称时收到错误很重要?

    是否可以创建一个新的模式,转移旧模式对象的所有者,然后删​​除旧模式,然后使用上面的方法?

    附:请参阅登录后触发器:http://psoug.org/reference/system_trigger.html

    附言由于您已经详细说明了您的要求:

    ...该表可能是使用数据库链接的同义词,或者该表可能由多个模式托管, 每个版本都有不同的版本。应该留给数据库来解析实际位置 客户端应用程序引用的对象。

    如果对象的位置不在 CURRENT_SCHEMA 中,而是在某个其他模式中,例如,这两个模式恰好都有名为 CUSTOMER 的表,数据库引擎将不知道客户端应用程序发送给它的语句如果表名不是那么限定,则应该引用其他模式。这意味着引擎不具备一定程度的元知识,尽管它为开发人员提供了以存储过程和触发器的形式创建此类智能的工具,并授予/撤销对对象的控制权。

    将这种智能置于后端的最佳成功机会是撤销对表和视图的所有直接权限,并要求客户端应用程序通过存储过程访问对象,因为数据库引擎本身并不了解事物像应用程序发布级别。我认为没有纯粹的声明方式来完成它。它在很大程度上必须是程序性的。您自己的后端逻辑必须负责在不同模式中的同名对象之间进行仲裁。也就是说,像 AFTER LOGON 触发器和 ALTER SCHEMA 这样的功能应该对您有所帮助。

    【讨论】:

    • 客户端代码在使用模式名称时收到错误很重要,因为它可能不是开发人员指定的名称。例如,该表可能是使用数据库链接的同义词,或者该表可能由多个模式托管,每个模式用于不同的版本。它应该留给数据库来解决客户端应用程序引用的对象的实际位置,而不是客户端应用程序,否则您会失去部署灵活性。
    【解决方案4】:

    你做不到。同义词只不过是指向其他模式对象的指针。您授予对实际对象的访问权限,而不是同义词。来自 Oracle 文档:

    http://download.oracle.com/docs/cd/B28359_01/server.111/b28310/views003.htm

    同义词本身是不安全的。当您授予同义词的对象权限时,您实际上是在授予基础对象的权限,并且同义词仅作为 GRANT 语句中对象的别名。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-07
      • 1970-01-01
      • 2010-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多