【问题标题】:Prevent Oracle package from being executed in production防止 Oracle 包在生产中执行
【发布时间】:2019-12-10 00:59:03
【问题描述】:

我创建了一个 Oracle PL/SQL 包,我想防止它在生产环境或特定数据库上执行,这可能很危险。事实上,事实证明我拥有管理员权限,并且可能会无意中在生产环境中编译开发包。

我尝试使用类似于以下内容的方式检查包正文中的上下文:

create or replace package body my_test_package is

    context varchar2(64);

    function get_context return varchar2 is
    begin
        -- return context: DEV or PROD
        ...
    end;

    -- list of other functions & procedures ....

    begin   
        if context = 'PROD' then
            dbms_standard.raise_application_error(-20001, 'production context, prevent execution of this package');
        end if;
end;

但是,我知道这是不好的解决方案,因为初始化时间只发生一次,正如Oracle documentation 所述:

包的初始化部分只起次要作用,因为与子程序不同,包不能被调用或传递参数。因此,包的初始化部分只运行一次,即您第一次引用该包时。

因此,这意味着将执行第一个过程调用之后的所有后续过程调用,即使在生产环境中也是如此。例如:

-- production environment
begin
    my_test_package.dangerous_procedure();
exception when others then
    dbms_output.put_line('bypass context exception');
end;
my_test_package.dangerous_procedure(); ---> EXECUTED IN PROD :(

是否有一种常见的习惯用法或已知的方法来防止包在特定环境中执行? (例如,不必在包的每个过程/函数中复制相同的代码,以检查它是否有权执行)。

谢谢

【问题讨论】:

  • 如果包中的程序永远不应该在特定环境中执行,为什么包需要存在于那个环境中?如果包需要存在于该环境中,为什么有人需要对包进行execute 访问?如果你真的希望包存在于你不希望它被执行的环境中,并且你真的想授予用户执行包中他们不应该执行的方法的权限,包中的每个方法都可以运行check_context 函数如果环境是您要避免的环境,则会引发错误。
  • @JustinCave 我想到了你的建议,例如check_context 函数,但这意味着在包中的每个函数/过程中大量复制同一段代码,对吗?恕我直言,这不是一个好方法。 /更新了我的问题
  • 如果您希望包存在并且您希望用户有权执行这些方法并且您希望这些方法在生产中做一些不同的事情,您需要更改所有公共的代码方法。如果您不喜欢在每个公共方法中调用 check_context 函数,您使用的是最新版本的 Oracle,并且您愿意放宽跨环境权限相同的约束,您可能会使用基于代码的访问控制,并且只授予包在某些环境中执行任何危险任务的权限。但这似乎是迂回的
  • 我不认为问题出在程序上,而是“可能无意中在生产环境中编译开发包”;对删除语句进行重大更改怎么样?无论如何,对于程序 2 选项浮现在脑海中。 Prod 中的特殊用户,可能“无意中在生产环境中编译开发包”;删除或截断的更新版本怎么样?无论如何,对于程序,我想到了 2 种方法:生产中的特殊用户和 conditional compilation
  • 生产环境中的第一个设置具有管理员权限的特定用户并从所有其他用户中删除这些用户。不要在开发中创建此用户。至于条件编译,只需放置条件语句,除非存在特定的外部条件,否则它不会编译。使用一个或两个。

标签: oracle plsql permissions package


【解决方案1】:

通常有相反的要求:即,您有在 PROD 中运行的进程,而您不想在 DEV 中运行(或不以相同的方式运行)。例如,您可能有一个程序生成一个文件并将其通过 FTP 发送给贸易伙伴。从 PROD 克隆后,您不希望它意外地在 DEV 中运行。

我们将需求实现构建到我们的代码中,而不是依赖于数据库级别的东西,例如在某些环境中删除对象(或在克隆后不断地在 DEV 实例中重新安装东西)和/或撤销安全性。通过将内容构建到我们的代码中,我们不仅可以灵活地防止某些东西在一个实例或另一个实例中运行,还可以让它运行但以不同的方式运行(例如,生成 FTP 文件,但发送它到测试服务器而不是贸易伙伴)。

为此,我们有一个具有生产数据库名称的数据(我们为此使用称为“配置文件值”的应用程序功能,但您可以将其放入自定义表中)。

那么,在任何环境敏感的过程中:

BEGIN
  l_db_name := xxcust_common_utils_pkg.get_production_dbname;  -- you write this function based on where you put the production database name...
  IF sys_context('USERENV','DB_NAME') = l_db_name THEN
    ... act like you want to in production
  ELSE
    ... act like you want to in non-production
  END IF;
END;

这很简单,但不幸的是需要编码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-01
    相关资源
    最近更新 更多