近来,公众和企业对于保护私有和私人信息的意识有了显著的增强。随着许多国家/地区现在出台了特定的法规,保护个人信息数据现在已经不仅仅是项公共关系事务,而且还是一项法定义务。
无论如何,保护 IT 系统(无论是在事务处理 (OLTP) 还是在数据仓库环境中)中的机密数据都是企业运营的首要考虑事项。例如,您能想象到一个在数据库中未存储客户姓名、地址和信用卡卡号的销售系统吗?私人数据是当前系统的战略资产,因此公司应采取一种具有积极和健壮的综合方法,通过安全策略实施来保护机密数据。从这个角度看来,组织的战略和战术决策必须以最终结果为导向,而不是集中于特定项目或当前的业务需要,从而避免重新设计而带来的高成本甚至是失去客户。
通常会采用许多复杂措施阻止在网络和操作系统级的未授权访问,并且将其集成到非定制或定制的应用程序系统中。而实际存储信息的的数据库却往往只使用标准的用户名/口令机制进行保护。Oracle 数据库 10g 对这一机制的实现是最好的,即使这样,如果口令泄密,那么保护也将随之不再存在了。Oracle 数据库可以通过 Oracle 虚拟专用数据库、Oracle 标签安全和其它机制提供更多保护,但这些机制在实际生产中仍未得到充分应用。
在这篇技术文章中,我将介绍(并通过演示说明)在假定一个或多个数据库口令已经泄露的情况下,如何实现安全机制。此方法提供了一种简单的方法来组合使用 Oracle 数据库 10g 第 1 版中安全特性(Oracle9i 中包含有其中的一部分特性),使得在入侵者即使建立了数据库连接的情况下,仍能实现高级别的保护。其主要目的是避免机密数据遭到未授权用户(无论该用户是外来的黑客还是公司内部的数据库管理员)的破坏。所提供的示例专用于事务环境,但这于原理同样可应用于商务智能和数据仓库环境中。
数据库安全性目标
Oracle 数据库是实际安全实施的重要组成。一般说来,运行 Oracle 数据库引擎的服务器得到了防火墙的很好保护,但这并不能排除未授权访问尝试(包括内部员工的访问尝试)的可能性。除了传统的用户名/口令方法之外,Oracle 数据库引擎还提供了自身的安全机制,以便即使在通过了其他所有安全障碍的情况下,仍能保护它的数据内容。以下各部分中确定的安全措施都假定入侵已渗透到数据库级别,这些措施将用作数据库自身的最后一道防线,但它们并不能用来代替外部保护。
在假定所有其他安全措施已被绕过,并且未授权数据库访问已经开始了的前提下,以下各部分定义的解决方案都用于构建数据库防御特性,以确保:
Oracle 应用服务器(作为数据库的安全客户端)可以在需要时读取、插入和更新所有数据。Oracle 应用服务器将使用它的内部安全机制和应用程序专用的安全机制来确保私人数据免遭表示层中的未授权用户的入侵。
使用 SQL*Plus,在错误解决过程中能够进行安全的数据库访问,包括能够查看机密信息。
其他数据库访问无法检索私人客户端信息。
演示安装
本练习包含一个典型的销售类型数据模型,其中要保护的数据存储在 CUSTOMER 数据库中,具体而言是 CARD_NO 列中。该示例使整个表对未授权请求显示为空,因此进行 SELECT * from CUSTOMER; 将检索不到任何记录。一个表面上看起来不包含任何记录的表将比包含记录但将“令人感兴趣”的列隐藏或屏蔽起来的表更不会引起入侵者的关注(他们认为前者可能根本未被使用)。
但对 DBMS_RLS.ADD_POLICY 调用稍微进行修改后,此解决方案将隐藏(显示为 NULL)或屏蔽(显示为 ****)受保护列 CARD_NO 的值,但显示其他列的值的记录。可以通过在 DBMS_RLS.ADD_POLICY 调用中指定 sec_relevant_cols 和 sec_relevant_cols_opt 参数来实现功能。本文的支持文件中的 initial_setup.sql 脚本创建了一个非常基本的 CUSTOMER 表,该表作为本过程中的示例。
最好避免使用模式所有者身份来访问数据;而是应一个不同的帐户(如 AppSvr),该帐户由所有客户端连接共享,并由 Oracle 应用服务器处理。AppSvr 数据库用户不拥有任何对象,并且只拥有 CREATE SESSION 系统权限,但拥有对所有包含模式所有者(如 SHIP2004 模式的所有者)应用程序数据的表的 SELECT、INSERT、UPDATE 和 DELETE 权限。
支持文件中的 enable_connection.sql 脚本创建一个通常由运行在 Oracle 应用服务器上的应用程序使用的用户(如上所述)。
安全性实施
为实现所述的安全目标,除非您“授权”了连接(由在预定的 IP 地址处运行的 Oracle 应用服务器启用),我们将使用一个数据库策略来隐藏 CUSTOMER 表中的记录,。此策略在安全管理器用户(如 Sec_Manager)下实现,因此即使从 SHIP2004 或 AppSvr 模式中也看不到它。
确定要使用的环境变量以及要由安全谓词检查的特定值是实现的问题。大量的潜在组合和特殊的网站详细信息将创建重要的入侵尝试障碍。
为安全实现中使用的所有定义创建一个没有任何权限(甚至是 CONNECT)的单独模式(如 Sec_Manager)作为占位符是比较可取的。所有对象将由 Sec_Manager 模式中的数据库管理员帐户创建。由于没有权限,此用户名甚至无法用于登录到数据库,因此所拥有的安全性定义将得到可靠地保护。(任何人甚至看不到与安全性相关的对象的定义。)
但本文最初的目标之一是为几个维护和支持人员成员实现 SQL*Plus 级别的访问。此紧急访问需要一个“安全通道”,它可以被授权用户轻松记住,但由于太长而无法写入到桌面即时贴中(可由任何人看到),这种由于所保留的口令数目所导致的不利情况。本示例使用 CLIENT_IDENTIFIER 环境变量,但它可以为您所选择的任何环境变量或环境变量组合。
create_setup.sql 脚本(位于支持文件中)演示了如何根据以上描述创建安全实现模式、谓词函数以及安全策略。它还生成了几个数据列表,并使用不同的数据库登录权限演示了将在 CUSTOMER 表中看到(或看不到)的不同连接。它还演示了如何使用 dbms_session.set_identifier 函数进行解密,以通过 SQL*Plus 连接访问数据。
直接的 SQL*Plus 访问
由于 Oracle 应用服务器具有强健的内置安全特性(用于验证和授权请求),因此直接的 SQL*Plus 访问是入侵者通常使用的入口点。实现如上所述的安全策略后,将具备以下功能:
即使 AppSvr 口令已被破坏,且某个人使用 AppSvr 登录以通过 SQL*Plus 进行未授权访问,CUSTOMER 数据也不会显示,这是因为 IP 地址和/或外部会话名称不是安全谓词所预期的—系统甚至不会显示受保护的表中存在有任何记录。
联网应用程序将不会使用模式所有者帐号登录。它将只用于维护目的,因此会严格控制它的发放人数。此外,它们将必须正确地完成一个或多个环境设置(本示例中为 CLIENT_IDENTIFIER)才能查看 CUSTOMER 数据。即使口令遭到破坏(例如,某个人找到桌面上的即时贴),只要安全谓词中隐藏的后门设置未被泄露,受保护的表也将对访问它的未授权用户显示为空。由于入侵者甚至不知道该表中存在数据,因此根本不可能对其进行进一步的研究。
任何其他数据库用户(甚至拥有数据库管理员权限的用户)都看不到受保护表中的记录。然而,即使其他数据库用户通过某种方式获得了 SHIP2004 表的访问权限,以上所述的注意事项也仍然有效。(用户必须了解安全特性才能看到私人数据。)
示例脚本中的数据列表演示了如上所述的内容。
加密数据和程序包
加密 CARD_NO 数据可以确保为机密数据再添加一层数据保护。可以使用外部进程中定义的静态密钥或数据库的列中存储的静态密钥进行加密。一个比较可取的方法是将加密组件(密钥和函数)划分到两个单独的服务器,以增加环境的复杂性和潜在的入侵者检索所有所需信息以解密受保护数据所需的工作量。
如果在应用程序中定义密钥,则攻击者将不但必须进入数据库服务器,而且必须进入应用服务器才能获得此密钥以解密数据。即使某个人攻破了以上各部分中描述的访问保护,他仍必须破解程序包代码(按下个部分“保护安全环境”中的描述进行编码)才能知道所应用的加密函数。攻击者还必须破解位于应用服务器中的已编译的应用程序代码才能识别所使用的密钥。如果此密钥未存储在任何明文文件(如参数文件或源代码)中,而是只存储在已编译的版本中,则通过未授权访问检索实际加密数据所需的技能和难度将随之提高。
但为了独立于应用程序,支持文件中演示的示例将其他表列用作加密密钥。密钥列中存储的值必须是静态的,这是因为如果该值更改,则 CARD_NO 数据将无法再被解密。在本示例中,我们为此密钥选择了 CREATED_BY 列,原因是记录创建后它将不会进行更新。
最大限度地减少加密所需的额外工作的最便捷的解决方案是创建一个程序包,该程序将用于从根本上隐藏对 Oracle 的加密实用程序调用。开发人员将只需生成一个函数调用而不是直接使用受保护的列,这是为获取安全保障而产生的一个很小的不便之处。本示例使用 DBMS_CRYPTO 程序包中的 ENCRYPT 和 DECRYPT 函数,该程序包提供了许多加密方法(有关其他详细信息,请参阅 Oracle 文档)。大量的选项组合(针对所选择的密钥)增加了攻破所提供解决方案的复杂度,尤其是按如下所述对定制程序包的源代码进行了打包后。(create_packages.sql 脚本为本文描述的加密/解密函数提供了示例设置。)
Oracle 数据库 10g 第 2 版提供了随取随用的透明数据加密,使您能够透明地加密任何常规数据库列(日期、字符串、数字)并在用户通过了必需的访问控制检查时自动将其解密。Oracle 引擎本身(不受数据库用户的控制)可以处理加密密钥,因此对表的应用程序或 SQL 访问不必再管理这些密钥。通过扩展,数据库管理员可以管理表但看不到实际的数据值,这将解决以上设置所涉及的部分问题。
操作加密数据
Oracle 应用服务器应用程序使用 Sec_Manager.Secure_Package 程序包中的例程存储加密格式的私人数据(如使用 Secure_Package.Secure_Data 存储 CARD_NO 数据)。根据 create_packages.sql(位于支持文件中)中描述的定制加密程序包的定义,对 CARD_NO 列的访问已被函数调用所取代,该函数调用的参数是要存储在列中的值以及用于数据解密的密钥。
例如,要将“a1b2c3d4”用作加密密钥,必须将最初如下所示的典型 INSERT 语句
insert into CUSTOMER (NAME, CARD_NO) values ('Jane Doe', '1234123412341234');
转换为:
insert into CUSTOMER (NAME, CARD_NO) values ('Jane Doe', Sec_Manager.Secure_Package.Secure_Data('1234123412341234','a1b2c3d4'));
同样,Oracle 应用服务器应用程序还使用 Sec_Manager.Secure_Package 中的例程读取加密格式的数据,如 CARD_NO 数据的 Secure_Package.Clear_Data。然后利用插入值时使用的加密密钥来以明文格式取回受保护信息。这种情况下,必须将最初为如下所示的典型 SELECT 语句
select NAME, CARD_NO from CUSTOMER;
修改为:
select NAME, Sec_Manager.Secure_Package.Clear_Data(CARD_NO,'a1b2c3d4') from CUSTOMER;
保护环境
当完成所有开发(希望由值得信任的人员完成)后,还可以将升级后的代码加密,以便甚至连升级脚本的数据库管理员都无法确切了解安全性的实现方法。通过 Oracle 提供的实用程序实现加密,可以使用如下所示命令
wrap iname=Secure_Package.sql oname=Secure_Package.sec
打包后,可以在 SQL*Plus 提示符后象执行任何明文脚本一样执行 Secure_Package.sec,且 Oracle 引擎还将对其进行解释。同一概念也可应用于任何其他与安全性相关的 PL*SQL 脚本。此方法不但禁止了参与代码升级的人员(数据库管理员、开发人员、支持和管理人员)查看程序包内容,而且程序包内容还以加密格式部署到数据库中,因此以后要尝试破解这些程序包内容是很难的。
即使具有数据库管理员权限的入侵者将 CONNECT 权限授予安全对象所有者 Sec_Manager 以查看保护和加密程序包的内容,也不会有任何明文会存储在这些对象的数据库中。由于 Oracle 未提供任何“解包”实用程序,因此入侵者将必须破解 Oracle 的加密算法才能够查看程序包内容。
在不区分访问的情况下审计对敏感数据的访问
即使所有安全措施都已经到位了,了解是否对机密数据进行了未授权访问仍很重要。最简单的方法是使用内置的数据库审计功能在表级别监视对受保护数据的访问(SELECT、INSERT、UPDATE、DELETE),而不管请求事务的数据库连接如何,命令如下:
audit insert, update, select on SHIP2004.CUSTOMER;
但使用 Oracle Fine Grained Auditing (FGA),您可以进一步改进访问监视以最小化处理开销并提供有意义的信息。enable_fga.sql 中提供的示例使用 DBMS_FGA 程序包启用基本的审计策略。数据库中的内置审计机制禁止用户绕过审计,从而确保了它的精确性。可以在 DBA_FGA_AUDIT_TRAIL 视图以及 DBA_COMMON_AUDIT_TRAIL 视图中查看审计记录,在策略指定 audit_trail = DBMS_FGA.DB_EXTENDED 的情况下,审计记录甚至可以包含 SQLBIND 和 SQLTEXT 信息。
可以使用 Oracle 提供的功能轻松地增强此处提供的示例,从而加入电子邮件或寻呼机通知和激活条件,以只生成特定事件的审计记录。有关数据库审计策略和实现的其他信息,请参阅 Oracle 文档。
结论
随着入侵尝试变得日益复杂,系统架构师和管理员必须定义更好的方法来保护他们的数据库内容。以非常的方式组合一系列常用方法可以使入侵者如同进入了迷宫,无功而返。
即使当 AppSvr 和 SHIP2004 模式的口令被“意外”泄露时,本文描述的方法也是行之有