2006 年,OTN 发布了我撰写的一系列题为“安全保护项目:一种分阶段的数据库基础架构保护方法”的文章。在这些文章中,我讨论了如何应对常见的安全挑战(如用户使用默认口令)以及如何扫描您的数据库以查找这些用户。
对我而言很不幸的是,您可能已经忘记了我文章中的那一部分。Oracle 数据库 11g 现在提供一种快速识别使用默认口令的用户的方法。该方法实施起来极为简单,只需检查单个数据字典视图:DBA_USERS_WITH_DEFPWD。(注意,DBA_ 是一个标准前缀,它不仅包含使用默认口令的 DBA 用户。)您可以执行以下命令来识别这些用户:
select * from dba_users_with_defpwd输出如下:
USERNAME ------------------------------ DIP MDSYS WK_TEST CTXSYS OLAPSYS OUTLN EXFSYS SCOTT MDDATA ORDPLUGINS ORDSYS XDB LBACSYS SI_INFORMTN_SCHEMA WMSYS由于 SCOTT 使用了默认口令 TIGER,因此您会看到他出现在上面的清单中。使用下面的语句进行更改:
SQL> alter user scott identified by tiger1; User altered.现在,如果您查看该视图:
SQL> select * from dba_users_with_defpwd;您就不会在该清单中看到 SCOTT 了。就这么简单!
在版本 11g 之前的 Oracle 数据库中,用户口令是不区分大小写的。例如:
SQL> conn scott/tiger Connected. SQL> conn scott/TIGER Connected.这种安排为支付卡行业 (PCI) 数据安全标准之类的标准带来了问题,这些标准要求口令区分大小写。
该问题得到了解决,在 Oracle 数据库 11g 中,口令也可以区分大小写。通过 DBCA 创建数据库时,系统会提示您是否希望升级到“新的安全标准”,其中之一就是区分大小写的口令。如果您接受该标准,口令在创建时的大小写状态将被记录下来。假如您接受了新标准,相应的操作结果如下:
SQL> conn scott/tiger Connected. SQL> conn scott/TIGER ERROR: ORA-01017:invalid username/password; logon denied Warning:You are no longer connected to ORACLE.注意对“tiger”和“TIGER”的不同处理方式。
现在,您的某些应用程序可能无法立刻传递大小写正确的口令。典型示例是用户输入表单:很多表单在接受口令时不会进行大小写转换。然而,在 Oracle 数据库 11g中,这种登录方式可能会失败,除非用户以区分大小写格式输入口令,或者开发人员对应用程序进行了修改,使其能够进行大小写转换(这一点不可能迅速实现)。
不过,如果您希望的话,仍然可以通过更改系统参数 SEC_CASE_SENSITIVE_LOGON 恢复到不区分大小写的状态,如以下示例所示。
SQL> conn / as sysdba Connected. SQL> alter system set sec_case_sensitive_logon = false; System altered. SQL> conn scott/TIGER Connected.在将现有 Oracle 数据库 10 g 升级到 11 g 时,可将口令移植到新标准。可以通过查询 DBA_USERS 视图来检查口令状态,尤其是新的 PASSWORD_VERSIONS 列。
select username, password, password_versions from dba_users; USERNAME PASSWORD PASSWORD ------------------------- ------------------------------ -------- SYSTEM 10G 11G SYS 10G 11G MGMT_VIEW 10G 11G您首先会注意到 PASSWORD 列为空,没有像 Oracle 数据库 10 g 和以前的版本中那样使用散列值填充。那么,口令出什么问题了?口令仍然存储在数据库中(在表 USER$ 中),但它在 DBA_USERS 视图中不可见。当用户被创建为全局或外部认证时,其状态指示为 GLOBAL 或 EXTERNAL,但不显示口令的散列值。
接下来,注意 PASSWORD_VERSIONS 列,它是 Oracle 数据库 11g 中新增的。该列表明口令是否区分大小写。值“10G 11G”的意思是,用户要么是在 10g 中创建然后移植到 11g 中的,要么是直接在 11g 中创建的。
如果您希望的话,在创建口令文件时,您也可以输入一个新参数 ignorecase 来实现 SYSDBA 口令的大小写区分,如下所示:
$ orapwd file=orapwPRODB3 password=abc123 entries=10 ignorecase=n在以上示例中,SYSDBA 的口令将为 abc123,而不是 ABC123 或任何其他大小写变体。
通过采用区分大小写的口令,不仅使得强行破解口令更为困难,同时能够使您满足更多合规性要求。更为重要的是,您可以动态地执行口令要求而不必关闭数据库。在进行升级或因升级原有应用程序而对登录问题进行调试时,这是非常有用的。
还记得 Oracle 数据库中的口令验证功能吗?很多人甚至可能都不知道它的存在,更不要说使用它了。该功能是快速、轻松地确保数据库口令的质量 — 例如,口令应当包含一定数目的字符,不应当与用户名相同,等等。也许它的最佳特色在于它是内置的,您只需要启用它即可。但很可能的是,您并没有启用该功能。
在 Oracle 数据库 11g 中,口令管理功能具有新的经过改进的验证逻辑。如果您查看 $ORACLE_HOME/rdbms/admin 下的口令验证文件 utlpwdmg.sql,您会发现脚本新建了一个名为 verify_fnction_11g 的口令函数。脚本末尾的语句如下所示:
ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 180 PASSWORD_GRACE_TIME 7 PASSWORD_REUSE_TIME UNLIMITED PASSWORD_REUSE_MAX UNLIMITED FAILED_LOGIN_ATTEMPTS 10 PASSWORD_LOCK_TIME 1 PASSWORD_VERIFY_FUNCTION verify_function_11G;脚本将该函数附加到概要文件 DEFAULT 中。除非明确分配了其他文件,该文件是所有用户的默认概要文件。这使得认证符合许多规定的要求。您要做的只是运行该脚本以创建 11 g 版的口令检查函数,该脚本将通过将自身附加到默认概要文件中来启用口令验证功能。
审计是另一个常见难题。Oracle 数据库包括强大的审计功能,可用于跟踪用户活动。大多数人由于担心 I/O 争用问题,并不利用审计功能。但事实上,一些审计可以被安全打开而风险却很小。
相关的示例包括 CREATE SESSION,它在会话开始时编写一条记录,然后在会话结束时更新该记录。该审计对 I/O 的影响极小,但带来了众多好处。
在 Oracle 数据库 11g 中,进行了两个简单的改动以提供更强大的审计解决方案。首先,数据库参数 audit_trail 现在默认情况下设置为 DB,在以前的版本中,它的默认值为 NONE。这允许您对任何对象、语句或权限打开审计,而无需重复使用数据库。
第二处改动是,默认情况下更多语句处于审计范围内。清单如下:
ALTER SYSTEM SYSTEM AUDIT CREATE SESSION CREATE USER ALTER USER DROP USER ROLE CREATE ANY TABLE ALTER ANY TABLE DROP ANY TABLE CREATE PUBLIC DATABASE LINK GRANT ANY ROLE ALTER DATABASE CREATE ANY PROCEDURE ALTER ANY PROCEDURE DROP ANY PROCEDURE ALTER PROFILE DROP PROFILE GRANT ANY PRIVILEGE CREATE ANY LIBRARY EXEMPT ACCESS POLICY GRANT ANY OBJECT PRIVILEGE CREATE ANY JOB CREATE EXTERNAL JOB如您所见,审计这些活动不会导致严重的 I/O 问题,因此,可将审计活动维持在可接受水平,同时对性能的影响最小。
这两处改动带来了一些强大的即需即用的审计功能。当然,它们只是一些数据库参数和审计设置;如果需要的话,您可以轻松地关闭它们。但如果您看看这些语句清单,您实际上会发现即使在开发数据库中,它们也是值得审计的。不过,您可能想对它们进行细微的调整。(例如,在数据仓库中,用户创建并删除大量临时表,因此审计 CREATE/DROP TABLE 可能会在审计线索中泛滥。)
(警告: 当您升级到 Oracle 数据库 11g 时,默认情况下上述语句的审计将打开。因此,审计线索将写入到 SYSTEM 表空间中的表 AUD$ 中,这些审计线索将迅速填充。密切关注该表空间。
由于各种新的法律法规,人们现在对加密的重视程度越来越高。您需要以某种方式对数据进行加密,但最大的问题在于如何加密?
对于仍然使用 Oracle 数据库 10g 第 1 版和以前版本的人来说,DBMS_CRYPTO 和 DBMS_OBFUSCATION_TOOLKIT 工具包允许您构建自己的加密框架。在 Oracle 数据库 10g 第 2 版中,该框架通过透明数据加密特性得以增强。
透明数据加密使您可以对特定列进行加密,这足以满足大多数要求。然而,性能仍然是该特性的一个问题(或者说,任何其他加密解决方案都存在着性能问题):索引范围扫描不能应用于加密列,这会对性能造成严重的负面影响。
这正是 Oracle 数据库 11g 中透明表空间加密的真正出色之处。当表空间声明已加密时,表空间(包括透明表空间、备份等)上的任何数据都已加密,而不仅仅是单独声明为已加密的表。但在进行索引扫描时,扫描发生在未对数据进行加密的内存中,因而不会对性能造成影响。
感觉激动吗?让我们看一下它的工作原理。加密过程与透明数据加密过程相同:您需要创建一个钱夹以存储主加密密钥。如果您还没有设置透明数据加密,则需要创建钱夹和密钥。
首先,创建钱夹的文件位置;默认位置为 $ORACLE_BASE/admin//wallet。默认情况下钱夹子目录并不存在,您需要进行创建。因此,在我的示例中,该目录为 /home/oracle/app/admin/PRODB3/wallet。
接下来,执行下面的语句以在钱夹中创建加密密钥:
alter system set encryption key identified by "abcd1234!";该语句同时创建钱夹和密钥。如果您现在检查该目录,您会看到刚刚创建的钱夹文件 (ewallet.p12)。
$ cd /home/oracle/app/admin/PRODB3/wallet $ ls ewallet.p12钱夹要使用口令才能打开,在本例中,口令为 abcd1234!。该语句也可以打开钱夹。以后,您无需再创建钱夹了。数据库启动后,您只需通过执行以下语句来打开钱夹:
alter system set wallet open identified by "abcd1234!"有关钱夹的更详细的讨论,请阅读 这篇 Oracle Magazine 文章。
现在创建表空间:
create tablespace secure1 datafile '/home/oracle/oradata/PRODB3/secure1_01.dbf' size 1M encryption using 'AES128' default storage (encrypt) /子句“encryption using ... default storage (encrypt)”将表空间标记为经过加密的。(注:我们对此表空间使用了 AES 128 位加密算法。其他选择包括 Triple DES 168 位密钥算法、AES 192 位密钥算法和 AES 256 位密钥算法。)
既然已经创建了表空间,您就可以像在常规表空间中那样创建表了。
create table secure_trans tablespace secure1 as select * from trans where rownum < 201 / create table secure_res tablespace secure1 as select * from res where rownum < 201 /上述语句在加密的表空间 SECURE1 中创建了表。为进行比较,以正常方式(不加密)创建另一个名为 INSECURE1 的表空间,并在其中创建表 INSECURE_TRANS 和 INSECURE_RES。INSECURE_TRANS 和 SECURE_TRANS 在结构和数据方面相同,但位于不同的表空间中。SECURE_RES 和 INSECURE_RES 也是如此。
现在更新这些表中的一个文本字段,以便在数据文件中搜索该字段:
update secure_trans set comments = 'Transaction Comments'; update insecure_trans set comments = 'Transaction Comments'; commit;通过使表空间先脱机再联机,将内容强制写到磁盘上:
alter tablespace secure1 offline; alter tablespace secure1 online; alter tablespace insecure1 offline; alter tablespace insecure1 online;此时,缓存中的数据已经写到磁盘上。搜索该字段,看会发生什么?
$ strings insecure1_01.dbf | grep Transaction Transaction Comments ...该字符串以明文形式出现在数据文件中。现在,对经过加密的 SECURE1 表空间执行同样的操作。
$ strings secure1_01.dbf | grep Transaction $该操作不会返回任何结果,因为数据文件是加密的,您不会以明文形式看到各列的值。一切都完美无缺,但性能怎么样呢?我们运行以下查询来体验一下。
select hotel_id, sum(amt) from secure_trans t, secure_res r where t.res_id = r.res_id group by hotel_id运行该查询时,我们也会对其进行跟踪。下面是跟踪文件的节选。
call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 14 0.01 0.01 4 6 0 186 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 16 0.01 0.01 4 6 0 186 Rows Row Source Operation ------- --------------------------------------------------- 186 HASH GROUP BY (cr=6 pr=4 pw=4 time=5 us cost=8 size=10400 card=200) 200 HASH JOIN (cr=6 pr=4 pw=4 time=45 us cost=7 size=10400 card=200) 200 TABLE ACCESS FULL SECURE_TRANS (cr=3 pr=2 pw=2 time=8 us cost=3 size=5200 card=200) 200 TABLE ACCESS FULL SECURE_RES (cr=3 pr=2 pw=2 time=9 us cost=3 size=5200 card=200)现在,对 INSECURE_RES 和 INSECURE_TEST 运行相同的测试,它们处于正常的(未加密的)表空间内。
call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ---------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 14 0.00 0.01 4 6 0 186 ------- ------ -------- ---------- ---------- ---------- ---------- ---------- total 16 0.01 0.01 4 6 0 186 Rows Row Source Operation ------- --------------------------------------------------- 186 HASH GROUP BY (cr=6 pr=4 pw=4 time=4 us cost=8 size=10400 card=200) 200 HASH JOIN (cr=6 pr=4 pw=4 time=46 us cost=7 size=10400 card=200) 200 TABLE ACCESS FULL INSECURE_TRANS (cr=3 pr=2 pw=2 time=8 us cost=3 size=5200 card=200) 200 TABLE ACCESS FULL INSECURE_RES (cr=3 pr=2 pw=2 time=9 us cost=3 size=5200 card=200)注意各例中的执行时间,它们都是相似的。因解密而导致的 CPU 消耗也并不显著。因此,表空间加密不会对性能产生影响。
DBA_TABLESPACES 视图有一个新列 ENCRYPTED,该列用于显示某个表空间是否已加密。此外,一个名为 V$ ENCRYPTED_TABLESPACES 的新视图用于显示针对该表空间启用的加密类型。
SQL> desc v$encrypted_tablespaces Name Null?Type ----------------------------------------- -------- ------------ TS# NUMBER ENCRYPTIONALG VARCHAR2(7) ENCRYPTEDTS VARCHAR2(3) SQL> select * from v$encrypted_tablespaces; TS# ENCRYPT ENC ---------- ------- --- 5 AES128 YES该视图可以和 V$TABLESPACE 视图的 TS# 列结合,以获得完整的信息。下面是该视图的外观:
SQL> desc v$tablespace Name Null?Type ----------------------------------------- -------- ------------ TS# NUMBER NAME VARCHAR2(30) INCLUDED_IN_DATABASE_BACKUP VARCHAR2(3) BIGFILE VARCHAR2(3) FLASHBACK_ON VARCHAR2(3) ENCRYPT_IN_BACKUP VARCHAR2(3)注意,ENCRYPT_IN_BACKUP 列和透明表空间加密没有任何关系。相反,它是备份期间表空间的 RMAN 加密,是在 Oracle 数据库 10 g 第 2 版中引入的。
如您所见,透明表空间加密以一种相当完美的方式解决了两个问题:它对磁盘上处于静止状态的数据进行加密,由于数据管理发生在 SGA 内,因此不会影响性能。
Oracle 数据库 10g 引入了用于数据移动的最强大的特性之一:Data Pump,它用于代替原来的导出/导入工具。除了速度更快之外,Data Pump 还具有很多优点,如并行化进程和重新映射表空间。在 Oracle 数据库 11g 中,它还通过一个新参数 ENCRYPTION 来帮助保护转储文件的安全。
转储文件位于数据库和数据库安全领域之外,并且包含潜在的敏感数据。在如今的安全意识环境中,它们构成了一组独特的问题。在一些真正具有安全意识的环境中,DBA 在导出数据后通过第三方实用程序对转储文件进行加密 — 如果导出工作量巨大,这不是一个非常方便的方法。
首先,我们了解一下典型转储文件的易受攻击程度。假设您有一个名为 TRANS 的表,它包含一个名为 COMMENTS 的列。该列中的值为“Transaction Comments”。如果您以正常方式导出该表:
$ expdp scott/tiger tables=trans dumpfile=insec.dmp directory=tmp_dir检查转储文件以查看该列值是否存在:
$ strings /tmp/insec.dmp | grep Transaction将出现大量匹配项。转储文件中的数据未加密,处于明文状态。
现在,使用新参数 ENCRYPTION 执行导出。您还必须指定要使用的算法类型。我们将使用 AES 128 位算法。
$ expdp scott/tiger tables=trans dumpfile=sec.dmp directory= tmp_dir encryption=data_only encryption_algorithm=aes128 Export:Release 11.1.0.5.0 - Beta on Sunday, 22 July, 2007 18:17:30 Copyright (c) 2003, 2007, Oracle.All rights reserved. Connected to:Oracle Database 11g Enterprise Edition Release 11.1.0.5.0 - Beta With the Partitioning, Oracle Label Security, OLAP, Data Mining and Real Application Testing options Starting "SYS"."SYS_EXPORT_TABLE_01": '/******** AS SYSDBA' tables=scott.insecure_trans dumpfile= sec.dmp directory=tmp_dir encryption=data_only encryption_algorithm=aes128 Estimate in progress using BLOCKS method... Processing object type TABLE_EXPORT/TABLE/TABLE_DATA Total estimation using BLOCKS method:64 KB Processing object type TABLE_EXPORT/TABLE/TABLE . . exported "SCOTT"."TRANS" 16.82 KB 200 rows Master table "SYS"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded ****************************************************************************** Dump file set for SYS.SYS_EXPORT_TABLE_01 is: /tmp/sec.dmp Job "SYS"."SYS_EXPORT_TABLE_01" successfully completed at 18:17:44在 此 转储文件中搜索是否存在该文本字符串:
$ cat /tmp/sec.dmp | grep Transaction $由于转储文件中的值是经过加密的,不是明文,因此不会出现任何匹配项。
“但是等一下”,您会说,“加密不需要密钥吗?我们将要使用的密钥传递到什么地方了?更重要的是,解密时如果没有密钥如何解密呢?”
答案非常简单:密钥将来自于您在前面看到的透明表空间加密中使用的钱夹。您无需为了使用 Data Pump 加密而使用透明表空间加密特性,但您需要执行相关步骤来创建钱夹。不必说,在加密和解密过程中,钱夹必须是打开的。
如果您熟悉 Data Pump 工具,您可能会想起一个类似的特性是通过参数 ENCRYPTION_PASSWORD 实现的。现在,您可能想知道二者有何区别。
问得好。10g 版对那些处于透明数据加密状态的列进行加密,而不是对整个转储文件进行加密。如果您不使用透明数据加密,就不会进行转储文件加密。在该工具的 11g 版中,无论是否使用了透明数据加密,您都可以对转储文件进行加密。这会为您带来更大的灵活性,同时具有一些实用价值。您可能不想对数据库中的数据进行加密,原因有很多,性能和增加的安全性是最明显的原因。但当数据位于数据库领域之外时,您一定希望对它们进行加密。在这种情况下,Data Pump 加密的威力就无可匹敌了。
您可能熟悉 UTL_TCP、UTL_HTTP 和 UTL_SMTP 这些程序包,它们支持数据库领域外的服务器之间的通信。例如,utl_tcp 用于在两台主机间建立 TCP/IP 通信,而不是通过数据库链接。类似地,utl_http 用于从 Web 服务器发出 http 请求,utl_smtp 用于在主机间进行 SMTP 邮件呼叫。
开发人员偶尔会使用这些强大的工具 — 例如,使用 utl_smtp 从数据库内发送邮件,使用 utl_http 提取可在 PL/SQL 程序内处理的 Web 页面等等。然而,这些工具带来了巨大的安全风险。使用 utl_tcp,数据库用户可以到达该主机可到达的任何其他计算机,甚至不会遇到系统提示。这曾是 Voyager 蠕虫的惯用伎俩,该病毒一年前刚骚扰过 Oracle 用户社区。
为了消除这一风险,很多专家建议撤消“从公网执行”这些程序包的权限。在我的“安全保护项目”系列文章中,我也推荐了这种方法。但如果开发人员出于合理原因希望执行这些程序包,该怎么办?
Oracle 数据库 11g 有一个新的解决方案:您可以将执行权限程序包授予任何人,但要控制他们可以调用的资源。例如,utl_tcp 可限制为仅调用几个 IP 地址,这种机制称为访问控制列表 (ACL)。如果主机在 ACL 中,用户可以在 utl_tcp 中使用;但是仅仅拥有对 utl_tcp 的执行权限是不够的。因此,恶意进程不可能取代 utl_tcp 程序包和建立非法连接。
我们来看一下它的工作原理。首先,创建一个 ACL:
begin dbms_network_acl_admin.create_acl ( acl => 'utlpkg.xml', description => 'Normal Access', principal => 'CONNECT', is_grant => TRUE, privilege => 'connect', start_date => null, end_date => null ); end;此处,参数 principal => 'CONNECT' 表示该 ACL 适用于 CONNECT 角色。您可以在此处定义一个用户或角色。该 ACL 是作为一个 utlpkg.xml 文件创建的。
创建完毕后,您可以进行检查以确保该 ACL 已增加:
SELECT any_path FROM resource_view WHERE any_path like '/sys/acls/%.xml';输出结果如下:
ANY_PATH ---------------------------------------------------------------------------- /sys/acls/ANONYMOUS/ANONYMOUS3553d2be53ca40e040a8c0680777c_acl.xml /sys/acls/OLAP_XS_ADMIN/OLAP_XS_ADMIN3551b25f93feb8dde040a8c068075b7_acl.xml /sys/acls/OLAP_XS_ADMIN/OLAP_XS_ADMIN3551b25f944b8dde040a8c068075b7_acl.xml /sys/acls/OLAP_XS_ADMIN/OLAP_XS_ADMIN3551b25f948b8dde040a8c068075b7_acl.xml /sys/acls/OLAP_XS_ADMIN/OLAP_XS_ADMIN3551b25f94cb8dde040a8c068075b7_acl.xml /sys/acls/all_all_acl.xml /sys/acls/all_owner_acl.xml /sys/acls/bootstrap_acl.xml /sys/acls/ro_all_acl.xml /sys/acls/ro_anonymous_acl.xml /sys/acls/utlpkg.xml注意输出结果中的最后一行,它显示您刚刚创建的 ACL。接下来,为该 ACL 增加一个权限。在本示例中,您将尝试将该 ACL 局限于用户 SCOTT。您还可以定义开始和结束日期。
begin dbms_network_acl_admin.add_privilege ( acl => 'utlpkg.xml', principal => 'SCOTT', is_grant => TRUE, privilege => 'connect', start_date => null, end_date => null); end;分配将受该 ACL 制约的主机以及其他详细信息:
begin dbms_network_acl_admin.assign_acl ( acl => 'utlpkg.xml', host => 'www.proligence.com', lower_port => 22, upper_port => 55); end;在本示例中,您指定“用户 SCOTT 只能调用主机 www.proligence.com,并且只能使用 22 到 55 端口。”现在让我们来试一下:
SQL> grant execute on utl_http to scott 2 / Grant succeeded. SQL> conn scott/tiger Connected. SQL> select utl_http.request('http://www.proligence.com') from dual; select utl_http.request('http://www.proligence.com') from dual * ERROR at line 1: ORA-29273:HTTP request failed ORA-06512:at "SYS.UTL_HTTP", line 1577 ORA-24247:network access denied by access control list (ACL) ORA-06512:at line 1注意错误“ORA-24247:network access denied by access control list (ACL)”。用户在端口 80 上调用 http 服务器,由于该服务器在允许的 22-55 范围之外,因此该操作被阻止。
现在,添加另一条规则以允许该通信:
1 begin 2 dbms_network_acl_admin.assign_acl ( 3 acl => 'utlpkg.xml', 4 host => 'www.proligence.com', 5 lower_port => 1, 6 upper_port => 10000); 7* end; 8 / PL/SQL procedure successfully completed. SQL> conn scott/tiger Connected. SQL> select utl_http.request('http://www.proligence.com') from dual; UTL_HTTP.REQUEST('HTTP://WWW.PROLIGENCE.COM') -------------------------------------------------------------------------------- </iframe><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD><TITLE>Proligence Home</TITLE> <META http-equiv=Content-Language content=en-us> ...但该规则仅适用于 www.proligence.com。如果您调用其他 Web 站点,调用将失败,错误原因仍为 ORA-24247。这是最细粒度水平上的安全性。如果您的企业需要连接到主机 www.proligence.com,您可以在允许该连接的同时阻止对任何其他主机的访问,从而防止恶意用户使用该功能来访问所有其他的主机。
要了解 ACL 的详细信息,请查询 DBA_NETWORK_ACLS 视图:
select host, lower_port, upper_port, acl, aclid from dba_network_acls where ACL='/sys/acls/utlpkg.xml'; HOST --------------------------------------- LOWER_PORT UPPER_PORT ---------- ---------- ACL --------------------------------------- ACLID -------------------------------- prolin3.proligence.com 80 100 /sys/acls/utlpkg.xml 35D4278980DE6407E040A8C0680037D6 ... and so on ...在我看来,这是 Oracle 数据库 11 g 最好的新安全特性之一。
在许多组织中,临时或 QA 数据库都会经常根据生产数据库进行刷新,从而允许开发人员在投入生产前针对数据库运行生产前代码。然而,该过程存在潜在的安全问题 — 当数据从生产数据库刷新到 QA 数据库以保持同步时,可能会泄露敏感的数据元素。为了应对该风险,很多组织在非生产数据库中将敏感数据更换为某些无意义的值,这种做法称为数据屏蔽。例如,您可能希望临时用一个随机的 9 个字符的编号来更新社会保险编号,从而屏蔽真实的 SSN。
进行设想是很容易的,但进行更改可能就难了 — 您必须编写 SQL 脚本,确保进程是可重新启动的,小心避免系统崩溃等等。导入数据时,为什么不让 Oracle 来处理上述事宜呢?在 Oracle 数据库 11g 中,Data Pump 有一个新参数 remap_data,用于在导入过程中更改数据。
首先创建一个重映射函数:
create or replace package pkg_mask as function fn_mask_ssn (p_in varchar2) return varchar2; end; / create or replace package body pkg_mask as function fn_mask_ssn (p_in varchar2) return varchar2 is begin return lpad ( round(dbms_random.value (001000000,999999999)), 9,0); end; end; /该函数接受一个 varchar 变量,返回 9 个字符。我们将使用该函数来屏蔽 SSN。ACCOUNTS 表如下所示。
SQL> select * from rates; ACC_NO ACC_NAME ACC_SSN ---------- ------------------------------ --------- 1 John Smith 123456789 2 Jane Doe 234567890您要屏蔽 ACC_SSN 列,它是帐户持有者的 SSN。您使用 Data Pump 导出该表。导出时,您使用新参数 remap_data 屏蔽导出转储文件中的数据。
$ expdp scott/tiger tables=scott.accounts dumpfile= accounts.dmp directory=tmp_dirremap_data=accounts.acc_ssn:pkg_mask.fn_mask_ssn该参数将重映射函数 fn_mask_ssn 中生成的值放到 pkg_mask 程序包中。注意该参数的格式。它遵循以下模式:
[<SchemaName>.]<TableName>.<ColumnName>:[<SchemaName>.]<PackageName>.<FunctionName>
<ColumnName> 是您要屏蔽的值所属列的名称。实际的重映射逻辑位于 <PackageName>.<FunctionName> 内。现在,您可以将表导入到非生产数据库中。导入完成后,如果您检查该表的值:
SQL> select * from rates; ACC_NO ACC_NAME ACC_SSN ---------- ------------------------------ --------- 1 John Smith 645270861 2 Jane Doe 538996590注意各个 ACC_SSN 值是如何变化的。这些值是由我们在前面编写并储存在导出转储文件中的重映射函数 pkg_mask.fn_mask_ssn 生成的。当我们导入时,该值就被导入了。
如果您已经导出了表但没有使用该 remap_data 参数,则转储文件中的值已经是准确值。您可以在导入时屏蔽这些值,仍然使用这个神奇的参数。
$ impdp scott/tiger dumpfile=accounts.dmp remap_data= accounts.acc_ssn:pkg_mask.fn_mask_ssn directory=tmp_dir tables=accounts我们在此处使用了一个随机值函数,我们还可以使用任何其他逻辑。例如,假设要求将 SSN 除后四位之外的所有数字全部用 X 代替。这也很简单。您只需编写一个类似于下面的函数:
create or replace package pkg_mask as function fn_mask_ssn (p_in varchar2) return varchar2; end; / create or replace package body pkg_mask as function fn_mask_ssn (p_in varchar2) return varchar2 is begin return; 'XXXXX'|| substr (p_in,6,4); end; end; /打包的函数也是可重用的;它可用于对任何列的任何导入中。屏蔽数据的方法多种多样无穷无尽 — 只要您能创建一个可以返回一个值的函数,您就可以用它来屏蔽该值。这就减少了您的开发和维护任务,同时使得从生产数据库向非生产数据库进行安全的数据刷新成为可能。
在以前的版本中,大多数安全操作是通过一个名叫 Oracle Security Manager 的工具进行的。在 Oracle 数据库 11g 中,Oracle 企业管理器包括用于执行这些任务的所有工具。下面是数据库主页上 Server 选项卡的屏幕截图。注意右下方名为 Security 的部分。