内容


DB2 安全性,第 8 部分

数据库安全的 12 条军规

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: DB2 安全性,第 8 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:DB2 安全性,第 8 部分

敬请期待该系列的后续内容。

简介

在过去几年中,很多详细谈论大范围的系统安全问题的报道成为新闻的一大热点。通常,敏感的个人数据,例如社会保险号(SSN)、信用卡号和银行账号都是从不安全的系统中被窃取的,随之带来的后果是出现身份盗用、金融诈骗、未经授权地使用信息等现象。因此,系统管理员必须不断地监控他们的系统,确保系统中采取了适当的安全预防措施。

可在系统架构的不同级别上应用安全性。例如,可以通过安装防火墙来防止外部网络对服务器的未经授权的访问。可以使用一些安全网络协议技术,例如 IPSec,来保证网络上计算机间通信信道的安全性。又如,可以实行严格的密码策略,要求用户选择一个强密码,并经常更换密码。数据库级的安全措施,包括身份验证和授权,也可以用于加强应用程序的安全性。

本文描述了用于 DB2 for Linux、UNIX 和 Windows 的十二种最佳安全实践。这些最佳实践专门注重于可以通过数据库管理和编程进行控制的一些元素,但是不包括其他可应用于系统中更大范围内的安全技术或策略。本文中列出的最佳实践不分先后顺序,它们的重要性相当,都有助于提高 DB2 数据服务器的总体安全级别。

  1. 从 PUBLIC 撤销隐式的权限和特权
  2. 为 SYSxxx_GROUP 参数使用显式值
  3. 跟踪隐式的特权
  4. 不授予不必要的特权
  5. 使用加密的 AUTHENTICATION 模式
  6. 使用独立的 ID 创建和拥有对象
  7. 使用视图来控制数据访问
  8. 使用存储过程来控制数据访问
  9. 使用 LBAC 来控制数据访问
  10. 防止应用程序中的 SQL 注入
  11. 应用最新的 DB2 修复包
  12. 执行随机安全审计

从 PUBLIC 撤销隐式的权限和特权

DB2 在内部使用一个名为 PUBLIC 的伪组,对于 PUBLIC,可以为之授予特权,也可以撤销它的特权。PUBLIC 实际上不是在外部安全设施中定义的一个组,但通过它可以为通过 DB2 认证的用户授予特权。

当创建一个新数据库时,某些数据库权限和特权就会自动授予 PUBLIC,如 表 1 所示。

表 1. 创建数据库后被授予 PUBLIC 的权限和特权列表
权限或特权描述
BINDADD允许用户在数据库中创建新的包
CREATETAB允许用户在数据库中创建新的表
CONNECT允许用户连接到数据库
IMPLICIT_SCHEMA允许用户在不存在的模式中创建对象(动态地创建模式)
USERSPACE1 上的 USE 特权允许用户在 USERSPACE1 表空间中创建表或索引
NULLID 模式上的 CREATEIN允许用户在 NULLID 模式中创建对象
模式 SQLJ 上的 CREATEIN允许用户在 SQLJ 模式中创建对象
SYSPROC 模式上所有函数和过程上的 EXECUTE WITH GRANT 特权允许用户调用 SYSPROC 模式中的存储过程和执行该模式中的函数,并且可以将该许可授给其他用户
SQLJ 模式中所有过程上的 EXECUTE WITH GRANT 特权允许用户调用 SYSPROC 模式中的存储过程
NULLID 模式中创建的所有包上的 BIND 和 EXECUTE 特权允许用户绑定(BIND)和执行(EXECUTE)NULLID 模式中的包
SYSIBM 模式中表上的 SELECT 特权允许用户查看系统编目表中的信息
SYSCAT 模式中视图上的 SELECT 特权允许用户查看系统编目视图中的信息
SYSIBMADM 模式中管理视图上的 SELECT 特权允许用户查看这些管理视图中的信息
SYSSTAT 模式中编目视图上的 SELECT 特权允许用户查看系统编目视图中的信息
SYSTAT 模式中视图上的 UPDATE 特权允许用户更新这些系统编目视图中的统计信息

作为一项最佳实践,在创建一个新的数据库之后,应立即撤销这些被授给 PUBLIC 的隐式特权。

例如,您可以执行 清单 1 中显示的语句来撤销系统编目视图上的特权和其他被授予 PUBLIC 的隐式特权。不过这个清单还不是最全的。

清单 1. 创建数据库后撤销 PUBLIC 的隐式特权
CREATE DATABASE testdb;
CONNECT TO testdb;

REVOKE BINDADD ON DATABASE FROM PUBLIC;
REVOKE CREATETAB ON DATABASE FROM PUBLIC;
REVOKE CONNECT ON DATABASE FROM PUBLIC;
REVOKE IMPLICIT_SCHEMA ON DATABASE FROM PUBLIC;
REVOKE USE OF TABLESPACE USERSPACE1 FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.COLAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.DBAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.INDEXAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.PACKAGEAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.PASSTHRUAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.ROUTINEAUTH FROM PUBLIC; 
REVOKE SELECT ON TABLE SYSCAT.SCHEMAAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.SECURITYLABELACCESS FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.SECURITYPOLICYEXEMPTIONS FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.SEQUENCEAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.SURROGATEAUTHIDSFROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.TABAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.TBSPACEAUTH FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.XSROBJECTAUTHFROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.AUTHORIZATIONIDS FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.OBJECTOWNERS FROM PUBLIC;
REVOKE SELECT ON TABLE SYSCAT.PRIVILEGES FROM PUBLIC;
...
...

从 DB2 V9.1 开始,CREATE DATABASE 命令语法增加了 RESTRICTIVE 选项。如果该命令中包括了 RESTRICTIVE 选项,那么会导致 RESTRICT_ACCESS 数据库配置参数被设置为 YES,同时不自动授予 PUBLIC 任何特权。如果忽略了 RESTRICTIVE 选项,那么 RESTRICT_ACCESS 数据库配置参数被设置为 NO,前述所有特权都将自动授予 PUBLIC。

为 SYSxxx_GROUP 参数使用显式值

DB2 定义了一个超级用户权限层次结构(SYSADM、SYSCTRL、 SYSMAINT 和 SYSMON),每个权限可以执行一个子集的管理操作,例如创建数据库、强制使用户离开系统、进行数据库备份。与它们相关联的实例级参数(SYSADM_GROUP、SYSCTRL_GROUP、SYSMAIN_GROUP 和 SYSMON_GROUP)用于控制哪些用户可以继承那样的权限。

每个参数可以被设置为拥有该权限的一个用户组(在外部安全设施中定义)的名称。设置好之后,指定组中的所有用户就继承了该权限。

例如,如果有一个名为 DBAGRP1 的操作系统组,所有 DBA 用户都是这个组的成员,如果使用 清单 2 中所示的命令将 SYSADM_GROUP 实例参数的值设为 DBAGRP1,那么这个组中的所有用户都将继承 SYSADM 权限。

清单 2. 更新 SYSADM_GROUP 实例参数
UPDATE DBM CFG USING SYSADM_GROUP dbagrp1
db2stop
db2start

在 Windows 上进行缺省的 DB2 安装时,这些参数的值被缺省地设置为 NULL。这意味着超级用户权限被授给属于本地 Administrators 组的所有有效用户账户。在 Linux 和 UNIX 平台上,NULL 值被缺省地赋给实例所有者的主组,完成安装后,缺省情况下这个组只包含用户 ID 和实例所有者。

作为一项最佳实践,应该将每个实例级权限参数的缺省值改为一个显式的组名,以防止意料之外的超级用户访问。

在小型企业中,一个 DBA 扮演着多种角色,那么这些参数可以设置为相同的组名。而在大型环境中,由多个 DBA 负责一个系统,因此可以使用不同的组名。除了确保这些参数具有显式值以外,还应该尽量确保参数值所指定的组中的所有用户都确实有必要成为这个组的成员。如果没有这个必要,那么应该从这个组中删除!由于用户和组账户的管理是在 DB2 之外处理的,因此 DB2 不会仔细检查用户应不应该成为一个组的成员。

跟踪隐式的特权

如前所述,创建一个新的数据库时,PUBLIC 被隐式地授予一些特权。实际上,并不是只有此时才会授予隐式的特权。在某些情况下,当一个用户创建一个数据库对象,例如一个表或者包的时候,或者当授予 DBADM 权限级别的时候,数据库管理器会隐式地将一些特权授给用户。理解被隐式授予的特权有哪些,这些隐式特权所蕴涵的安全意义,这一点非常重要。

表 2. 授予不同动作的隐式特权小结
动作授予执行该动作的用户的隐式特权
创建新的数据库
  • 将 GRANT of DBADM 权限以及 BINDADD、CONNECT、CREATETAB、 CREATE_EXTERNAL_ROUTINE、CREATE_NOT_FENCED_ROUTINE、IMPLICIT_SCHEMA、LOAD 和 QUIESCE_CONNECT 权限授予创建者(SYSADM 或 SYSCTRL)
  • 将 GRANT of BINDADD、CREATETAB、CONNECT 和 IMPLICIT_SCHEMA 授予 PUBLIC
  • 将 USERSPACE1 表空间上的 USE 特权授予 PUBLIC
  • 将 SYSPROC 模式中所有过程和函数的 EXECUTE WITH GRANT 特权授予 PUBLIC
  • 将 SQLJ 模式中所有过程上的 EXECUTE with GRANT 特权授予 PUBLIC
  • 将 NULLID 模式中所有包上的 BIND 和 EXECUTE 特权授予 PUBLIC
  • 将 SQLJ 和 NULLID 模式上的 CREATEIN 授予 PUBLIC
  • 将 SYSIBM 编目上的 SELECT 授予 PUBLIC
  • 将 SYSCAT 编目视图上的 SELECT 特权授予 PUBLIC
  • 将 SYSIBMADM 管理视图上的 SELECT 特权授予 PUBLIC
  • 将 SYSSTAT 编目视图上的 SELECT 特权授予 PUBLIC
  • 将 SYSSTAT 编目视图上的 UPDATE 特权授予 PUBLIC
授予 DBADM 权限
  • 将 GRANT of BINDADD、CONNECT、CREATETAB、CREATE_EXTERNAL_ROUTINE、CREATE_NOT_FENCED_ROUTINE、IMPLICIT_SCHEMA、LOAD 和 QUIESCE_CONNECT 授予目标用户
模式
  • 当显式地创建模式时,CREATEIN、ALTERIN、DROPIN 权限被授予创建模式的用户。
  • 当隐式地创建模式时,另外还有 CREATEIN 权限被授予 PUBLIC。
创建对象(表、索引、包)
  • 将 GRANT of CONTROL 授予对象创建者
创建视图
  • 仅当用户对视图定义中引用的所有表、视图和昵称均有 CONTROL 特权时,才为其授予 Grant of CONTROL 特权

作为一项最佳实践,应该仔细检查和跟踪执行某动作时所授予的隐式特权。如果以后撤销这个动作,那么应撤销任何隐式的特权。

例如,假设您一开始将 DBADM 权限授予用户 JEFF,而随后又您决定撤销此权限。为了撤销 JEFF 的 DBADM 权限,可以使用以下语句:

REVOKE DBADM ON DATABASE FROM USER jeff

执行该语句之后,JEFF 将不再拥有 DBADM 权限;然而,他仍然拥有数据库上的GRANT、BINDADD、CONNECT、CREATETAB、 CREATE_EXTERNAL_ROUTINE、CREATE_NOT_FENCED_ROUTINE、 IMPLICIT_SCHEMA、 LOAD 和 QUIESCE_CONNECT 权限,这些权限是在一开始授予 JEFF 权限时隐式地授给该用户的。这些权限需要显式地从 JEFF 撤销。

不授予不必要的特权

开发一个应用程序时,开发人员常常很早就开始考虑安全性问题。例如,开发人员通常会用一个超级用户账户(DBADM 或 SYSADM)来开发和测试他们的应用程序,以免在运行代码时不断碰到安全错误消息。通过使用 Control Center,很容易为一个用户授予所有数据库许可和权限,如 图 1 所示。

图 1. 通过 Control Center 授予许可
 Control Center 的 Add User 对话框
Control Center 的 Add User 对话框

通常,完成了应用程序的开发和测试阶段后,在开发过程中为解决安全错误消息而授予的许可仍然保留在那里,而实际上它们已经没有存在的必要了。

作为一项最佳实践,应仔细检查在安装和配置应用程序的过程中授予每个用户的特权。确保所有被授出的许可和特权都是确实有必要的。

对于不熟悉 DB2 安全模型的开发人员来说,他们往往因为贪图简单而通过 Control Center(见 图 1)为自己授予所有可用的特权,以避免安全错误消息。您应该确保所有被授出的许可和权限都是确实有必要的。

使用加密的 AUTHENTICATION 模式

身份验证是指使用一种安全机制对用户 ID 和密码进行验证的过程。用户和组的身份验证是在 DB2 外部的一个设施中,例如操作系统、域控制器或 Kerberos 安全系统中进行管理的。实际的身份验证位置由实例参数 AUTHENTICATION 的值来决定。有很多不同的身份验证模式,包括在 DB2 服务器上(使用服务器的安全设施)、在客户机上(允许 “单点” 访问)、在一个 Kerberos 安全设施上或者通过一个用户定义的 Generic Security Service(GSS)插件对用户进行身份验证。其他身份验证选项还包括当用户名和密码以及数据通过网络在客户机与服务器之间传输的时候,对它们进行加密。表 3 总结了各种加密的身份验证选项。

表 3. 加密的 AUTHENTICATION 模式总结
AUTHENTICATION 模式描述
SERVER_ENCRYPT
  • 规定在服务器上定义的安全设施上进行身份验证。如果在连接尝试期间指定了一个用户 ID 和密码,那么该用户 ID 和密码将与服务器上定义的有效用户 ID 和密码组合相比较,以确定是否允许该用户访问实例或数据库。
  • 在这种模式下,在网络上传输用户 ID 和密码时,它们将被加密。
KRB_SERVER_ENCRYPT
  • 规定服务器接受 KERBEROS 认证或加密的 SERVER 身份验证模式。
DATA_ENCRYPT
  • 规定服务器接受加密的 SERVER 身份验证模式和对用户数据的加密。
  • 使用这种身份验证类型时,以下用户数据也将被加密:
    • SQL 和 XQuery* 语句
    • SQL 程序变量数据
    • 完成对 SQL 或 XQuery* 语句的处理后,来自服务器的包括对数据的描述的输出数据。
    • 一个查询的部分或全部结果集数据。
    • Large object(LOB)数据流
    • SQLDA 描述
DATA_ENCRYPT_CMP
  • 规定服务器接受 SERVER 身份验证模式和对用户数据的加密。
  • 这种身份验证类型可以与不支持 DATA_ENCRYPT 身份验证类型的下级产品相兼容。这些产品可以使用 SERVER_ENCRYPT 身份验证类型,而不必加密用户数据。支持 DATA_ENCRYPT 身份验证类型的产品则必须使用它。
GSS_SERVER_ENCRYPT
  • 规定服务器接受基于 GSS API 插件的身份验证或加密的服务器身份验证模式。

* 注意:从 DB2 9 开始,XQuery 是官方支持的查询语言。

作为一项最佳实践,应该使用加密的身份验证模式。

应该为您的环境选择什么样的身份验证模式,这是由数据的敏感级别来决定的。如果所有数据都是敏感的,那么应该选择 DATA_ENCRYPT 身份验证模式,这种身份验证模式会对客户机和服务器之间传输的很多数据进行加密。如果只有一小部分数据是敏感的,那么可以选择使用 SERVER_ENCRYPT 模式,这样可以保证密码得到加密,而敏感数据则可以通过不同的机制来得到保护。

要更新 AUTHENTICATION 实例参数的值(在这个例子中就是 DATA_ENCRYPT 的值),可以使用 清单 3 中显式的命令。

清单 3. 更新 AUTHENTICATION 实例参数
UPDATE DBM CFG USING AUTHENTICATION DATA_ENCRYPT
db2stop
db2start

注意,AUTHENTICATION 参数是在实例级上设置的,这意味着在相同实例中创建的数据库将使用共同的身份验证模式。如果有两个数据库,每个数据库需要不同的身份验证模式,那么需要在不同的实例中创建这两个数据库。

使用独立 ID 创建和拥有对象

创建一个数据库对象时,此对象归执行 DDL 语句创建它的那个用户 ID 所拥有。如果那个用户 ID 后来不用了(例如这位用户离开了公司),或者如果该用户不再需要数据库对象上的数据库访问或权限,那么 DBA 必须撤销该用户的特权。这将导致其他有依赖关系的数据库对象或包失效(或者不起作用)。

一旦成功创建了数据库对象或包,只要对象的创建者或包的绑定者继续持有它所引用的数据库对象上必要的特权,那么这个数据库对象或包就被认为是有效的(而不是不起作用)。因此,当对象创建者或包的绑定者的特权被撤销时,包含静态 SQL 语句的对象和包将失效。

作为一项最佳实践,应该像 Technote 中描述的那样,使用独立的 ID 来创建和拥有对象。 .

这里简要描述一下这个过程:

  1. 在外部安全设施中创建一个新的用户 ID,并使这个用户 ID 无效,使之不能被使用。
  2. 从所有操作系统组中删除这个用户 ID,并确认已将该用户所属的用户或组的 CONNECT 特权撤销,以确保该用户 ID 不具有 CONNECT 权限。
  3. 当需要创建新的数据库对象时,或者必须执行其他的 DDL 语句时,再通过 GRANT 语句将执行该动作所需的必要特权授给这个新的用户 ID。例如,为了创建表 T1 上的一个视图,必须将表 T1 上的 SELECT 特权授给新的授权 ID:

    GRANT SELECT ON TABLE T1 TO USER <user_auth_id>

    将当前会话授权 ID 暂时设置为新的用户 ID。例如:

    SET SESSION_USER = <user_auth_id>

    在这个授权 ID 下,创建数据库对象和绑定包。例如,为了创建表 T1 上的视图,可以执行以下语句:

    CREATE VIEW V1 AS SELECT * FROM T1

  4. 创建好所有必需的数据库对象和包之后,使用组成员关系和组特权来控制对所创建的数据库对象和包的访问。

    GRANT SELECT ON VIEW V1 TO GROUP1
    GRANT EXECUTE ON PKG TO GROUP1

  5. 完成上述操作之后,执行以下两条语句,将当前会话授权 ID 重新设置成常规授权 ID:

    SET SESSION_USER = SYSTEM_USER

    or

    SET SESSION_USER = <user_auth_id>

这种方法可以确保使用一个独立的用户 ID 与创建数据库对象、绑定包和授予特权的角色相关联。随着时间的推移,面临着用户的来来去去,这样将大大简化数据库模式和特权的管理。

使用视图控制数据访问

控制表数据访问的一种常见方法是使用视图。您不必将整个表数据都公开给应用程序用户,而是可以基于表中的部分列创建一个视图。例如,假设 清单 4 中定义的表包含保险单信息:

清单 4. 包含保险数据的示例表定义
CREATE TABLE INSURANCE (
   CUSTID               INTEGER NOT NULL PRIMARY KEY、
   SALARY               FLOAT、
   RENEWAL_MONTH        VARCHAR(3)、
   SEX                  CHAR(1)、
   MARITAL_STATUS       CHAR(1)、
   NUM_DEPENDENTS       INTEGER、
   YEAR_1ST_POLICY      INTEGER、
   NUM_CLAIMS           INTEGER、
   CYCLES               INTEGER、
   AGE                  FLOAT、
   COMMUTE_DIST         FLOAT
);

假设某家保险公司的姐妹公司希望访问客户数据,以便分析客户数据,为客户提供更合适的产品。然而,假设根据法律该保险公司不能泄漏个人的年龄或他们索赔的金额。为了满足这些需求,可以在这个表上按照 清单 5 所示方式定义一个视图,视图中不包括客户的年龄和索赔历史:

清单 5. 前面包含保险数据的表上的示例视图的定义
CREATE VIEW ins_v1_sis_comp_1 AS 
    SELECT custid、 salary、 sex、 marital_status、 num_dependents、 year_1st_policy、 
           cycles、 age、 commute_dist
    FROM insurance;
);

于是,通过这个视图就可以控制对数据的访问,而不必使用基表。使用 GRANT 语句可以控制对视图的访问,以免所有用户都能查看数据。例如,您可以控制谁能对该视图执行 SELECT、INSERT、UPDATE 和 DELETE 操作。

作为一项最佳实践,在您想隐藏表中的部分列或行的时候,应该使用视图来控制对表的访问。底层表定义发生变化时,使用视图还有助于使应用程序不受到影响。和表一样,也可以授予视图上的特定特权。

此外,还可以添加谓词到视图定义中,以便进一步筛选数据,同时又使秘密信息得以隐藏。沿用前面的例子,如果只想查看 65 岁以上男性客户,则可以使用 清单 6 中的视图定义:

清单 6. 前面保险数据上的视图定义,进一步约束了返回行
CREATE VIEW ins_v1_sis_comp_1 AS
   SELECT custid、 salary、 sex、 marital_status、 num_dependents、 year_1st_policy、 
          cycles、 age、 commute_dist 
   FROM insurance
   WHERE age >= 65 AND sex = 'M';
);

这样仍可以满足不提供客户年龄的需求,同时又为姐妹公司提供了更多的信息,使之可进一步定制产品。

使用存储过程控制数据访问

控制对表数据的访问的另一种流行方法是使用存储过程。存储过程是一组 SQL 语句,这组 SQL 语句形成一个逻辑单元,用于执行特定的任务。存储过程是在数据服务器上创建和运行的,用于封装一组经常要运行的操作或查询。例如,一个雇员数据库上的操作(雇用、解雇、升职、查找)可以编写成存储过程,由应用程序来调用,而不是直接编写在应用程序中。存储过程可以带不同的参数和结果来编译和执行,它们可以有输入、输出和输入/输出参数的任意组合。清单 7 展示了一个存储过程的例子,该存储过程根据业绩评分评定雇员新的工资和奖金。

清单 7. 根据业绩评分评定雇员的工资和奖金
CREATE PROCEDURE UPDATE_SALARY (
	IN empNum  CHAR(6)、 
	IN rating  SMALLINT)
  LANGUAGE SQL
  BEGIN
    IF rating = 1 THEN
      UPDATE employee
        SET salary = salary * 1.10、 bonus = 1500
        WHERE empno = empNum;
    ELSE
      UPDATE employee
        SET salary = salary * 1.05、 bonus = 1000
        WHERE empno = empNum;
    END IF;
  END

该存储过程接受两个输入参数,即雇员号和一个评分,然后根据给定的评分更新该雇员的工资和奖金。对于获得评分 “1” 的雇员,为他加薪 10%,并提供 $1500 的奖金。对于所有其他评分,为雇员加薪 5%,并提供 $1000 的奖金。

作为一项最佳实践,应考虑使用存储过程来控制对数据的访问。通过对存储过程的调用,将直接允许对表的访问,因此,限制一个用户可以在表上执行的动作,也将同时控制什么用户可以调用存储过程。

如今,很多应用程序的数据库层都设计为存储过程。也就是说,所有数据库访问都是通过存储过程调用来执行的。想要执行某个事务(例如更新订单或者购买某个产品)的应用程序,只需从应用程序中调用存储过程。这种方法的一个附带的好处是,所有逻辑都集中放在一个地方,这使得管理和维护更加容易,而且也使其他应用程序可以重用其功能。这种方法与面向服务的架构(Service Oriented Architecture,SOA)非常吻合。

还可以通过 GRANT 和 REVOKE 语句控制对存储过程的访问。想要调用存储过程的用户需要被授予 EXECUTE 权限。根据绑定选项和 SQL 语句是静态还是动态,存储过程引用到的各对象可能需要更多的特权。

使用 LBAC 控制数据访问

DB2 9 中一个新的、令人激动的特性是基于标签的访问控制(Label Based Access Control,LBAC)。 LBAC 使您可以决定谁拥有不同行和列上的写访问权限,谁拥有读访问权限。

一种特殊的新的安全管理员权限(SECADM)被用于配置 LBAC,具体做法是创建安全策略,安全策略实际上定义了用于决定谁可以访问什么数据的标准。创建好安全策略后,安全管理员创建安全标签,安全标签也是安全策略的一部分。标签可以基于任何标准,例如工作名称、用户是否是管理人员或者用户是否属于某个特定的部门。创建好安全标签之后,便可以将安全标签与表中的行和列相关联,以保护其中保存的数据。安全管理员通过为用户授予安全标签来允许用户访问受保护的数据。当一个用户试图访问受保护的数据时,该用户的安全标签将与用于保护该数据的安全标签相比较。

安全管理员还可以为用户授予豁免权(exemption)。豁免权使用户可以访问其安全标签不允许其访问的受保护数据。如果一个用户试图访问一个受保护的列,而他们的 LBAC 凭证又不允许他们访问该列,那么这样的访问将失败,用户收到一条错误消息。

作为一项最佳实践,应考虑使用 LBAC 作为控制对敏感数据的访问的一种方法。LBAC 很容易配置,您可以对它进行定制,以满足特定的安全环境。仅凭 DB2 9 中这一个令人兴奋的安全新特性,就完全值得考虑移植到 DB2 9。

很多应用程序在本地实现类似的基于行和列的安全访问机制。为什么不让开发人员将精力集中在业务逻辑的开发上呢?现在,使用这种非常易于定制的新安全特性,可以轻松为数据服务器提供这样的功能。

防止应用程序中的 SQL 注入

随着 Web 应用程序取代传统的客户机-服务器应用程序,从一开始就必须将安全性设计到系统中。基于 Web 的应用程序中一个常见的安全漏洞就是所谓的 SQL 注入(SQL Injection)。SQL 注入这种技术使攻击者可以利用应用程序中未仔细检查的输入机会来执行未经授权的 SQL 命令,而应用程序的本意是使用该输入来构造动态 SQL 查询。SQL 注入通常发生在 Web 应用程序用未检查的输入变量组合一个查询的字符串的时候,在这种情况下,攻击者可以添加另一个查询,或者修改查询,以获得他们不该拥有的信息或访问权。

例如,考虑下面的 PHP 代码片段:

$sql = 'SELECT * FROM staff WHERE empID="'.$_GET['empid'].'"'
$stmt = db2_prepare($conn、 $sql);
$result = db2_execute($stmt、 array(10));

这个查询从 STAFF 表中选择雇员 ID 等于从一个表单获得的一个值的所有行。这条语句就容易受到 SQL 注入的威胁 —— $_GET['username'] 中的引号没有转义,因此将被加入到语句文本中,这样可以导致恶意的行为。

如果在运行时 $_GET['empid'] 的值如下所示,想想会出现什么情况:

" OR 1=1 OR empID = "

把这个值加入到原有的表达式时,查询就变为:

SELECT * FROM staff WHERE empID = "" OR 1=1 OR empID = ""

这条语句将从表中选择所有的行,从而可能暴露保密信息。虽然这个特例的后果可能并不太严重,但完全有可能添加更恶意的代码,尤其是会修改表的 DELETE 或 UPDATE 语句。

作为一项最佳实践,在编写应用程序时应该保持安全意识。避免检索冗余的数据,并仔细检查所有输入值。

SQL 注入攻击主要是利用安全意识不够的程序员编写的代码。为了防止这种攻击, PHP 手册 提出了一些建议,包括:

  • 不要信任任何类型的输入,即使它来自一个选择框、隐藏的输入字段或一个 cookie。
  • 不要以拥有超级权限或者数据库所有者的用户身份连接到数据库。总是使用只有有限特权的定制用户。
  • 检查给定的输入是否具有预期的数据类型。PHP 之类的语言有很多输入验证函数。
  • 使用特定于数据库的字符串转义函数来引用传递给数据库的用户提供的值。
  • 不管使用什么手段,不要输出任何特定于数据库的信息,尤其是关于模式的信息。

应用最新的 DB2 修复包

DB2 修复包包含 bug 修复、新的特性和性能增强。DB2 修复包通常是按季度定期发布的,可以从 DB2 Technical Support 网站上免费下载。

修复包是累积式的。例如,FixPak 10 也包含 FixPak 9、FixPak 8、FixPak 7 等修复包中的修复,所以只需下载最新的修复包即可使用之前版本的修复包中的所有更新。

如果想查看当前安装的 DB2 的版本和修复包的级别,可以在命令窗口中使用 db2level 命令。该命令的输出将显示您的实例是多少位的 —— 32 位还是 64 位,另外还显示当前安装的修复包的级别和安装目录。

作为一项最佳实践,应该使用最新的修复包级别开发所有新的应用程序。这样一来,就可以利用所有最新的性能增强和修复。对于已有的应用程序,如果最新的修复包中包含可以解决重要安全问题的修复,那么应该考虑将应用程序移植到最新的修复包。

下载的修复包包含用于升级您的安装的代码和支持文档。 aparlist.txt 和 aparlist.html 文件中包含有该修复包已修复的一个 APAR 列表,也称产品缺陷。如果您在当前级别的 DB2 中遇到不正确的或意料之外的行为,那么可能是由于某项产品缺陷。您可以查看 APAR 文件,看看该修复包是否包含对这个产品缺陷的修复。修复包的 README 文件,即 FixPackReadme.txt 文件,包含关于安装的说明。在开始安装一个修复包之前,应该阅读这个文件,以便理解应该遵循的步骤的顺序。最后,release.txt 和 relnotes.pdf 文件中含有修复包的发行声明,其中包含关于 DB2 产品的最新信息,以及已知的问题和回避办法。

执行随机安全审计

最后,任何前摄性安全计划都应该包括随机的安全审计。这些审计需要记录数据库事件,例如授权检查、数据库对象维护、安全维护、系统管理和用户验证,并确保访问模式正常。

幸运的是,DB2 附带了一个审计工具,该工具可以生成一个 DBA,并允许 DBA 维护一系列预定义数据库事件的审计追踪。审计发生在实例级,这意味着审计一旦开始,它就会审计针对该实例中所有数据库的活动。审计功能可以监控不同类型的数据库事件,您可以指定只记录成功的事件还是只记录失败的事件,或者两种事件都记录。

可以使用 db2audit 命令来配置和操作审计功能。完成审计的配置并且生成了审计记录后,可以将审计记录提取到一个文本文件中,之后便可以对该文件进行分析。还可以将审计记录提取到有分隔符的 ASCII 文件中,之后可以将该文件装载到 DB2 关系表中,以便对其进行分析和查询。

例如,假设您从某个应用程序用户那里得到匿名举报,说有一个名为 SAM 的用户正在试图获取他原本无权访问的数据库对象和表的访问权。于是您决定随机监控 DB2 实例,以期发现失败的授权验证尝试。

在午餐时间的一个小时内,您首先对审计功能进行配置,使之审计 CHECKING 事件类型,只记录失败的尝试,并且使用 NORMAL 错误处理:

db2audit configure scope checking status failure errortype normal

中午 12 点,您启动了审计功能:

db2audit start

在审计期间,SAM 来到数据库服务器,并完成登录。他打开一个命令行窗口,连接到 SAMPLE 数据库,并尝试更新 EMPLOYEE 表中的雇员工资(当然这样的尝试会遭到失败)。他发出以下 SQL 语句:

connect to sample user sam using bad123boy
update tedwas.employee set salary = salary * 1.5

于是收到以下错误消息:

DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0551N "SAM" does not have the privilege to perform operation "UPDATE" on
object "TEDWAS.EMPLOYEE". SQLSTATE=42501

表明他没有更新那个表的许可,他快速退出服务器,并离开现场,自以为没有人注意到这一切。

一个小时过去了,您决定检查审计日志的内容。于是将 db2audit.log 文件中的记录提取到带分隔符的 ASCII 文件中:

db2audit extract delasc delimiter ; category checking database sample status failure

为了让之前创建的 DB2 表保存审计数据,使用以下命令将从 checking.del 文件中提取的数据装载到 CHECKING 表中:

LOAD FROM checking.del OF del MODIFIED BY CHARDEL; INSERT INTO audit.checking

您可以查询 AUDIT.CHECKING 表,以发现关于失败的授权尝试的更多信息:

SELECT category、 event、 appid、 appname、 userid、 authid FROM audit.checking

清单 8 中显示的查询结果中,您可以看到有一条关于失败的更新语句的审计记录。

清单 8. 查询 CHECKING 表的结果
SELECT category、 event、 appid、 appname、 userid、 authid FROM audit.checking


CATEGORY EVENT             APPID                    APPNAME           AUTHID
------------------------  -----------------------  ----------------  ------------
CHECKING CHECKING_OBJECT  *LOCAL.DB2.060206220334   db2bp.exe         SAM

1 record(s) selected.

这个输出可以证实 SAM 曾经尝试访问他无权访问的一个表。现在,您的怀疑得到了证实,您可以继续收集更多的证据提交给管理层,以便他们采取纠正措施。

作为一项最佳实践,应该对数据库执行随机安全审计。您也可以在得使您相信有人试图威胁系统安全的信息后,执行审计。

DB2 审计功能非常强大,可以为您提供审计访问尝试时所需的详细信息。虽然对未预见到的事件进行被动的监控是不可避免的,但是您应该使前摄性的审计成为安全计划中的重要组成部分,并且在一个月内抽出不同的时间来执行监控和分析。

结束语

本文介绍了十二种 DB2 的安全最佳实践 —— 从使用加密的身份验证模式一直到执行安全审计。随着越来越多系统安全问题的出现,监控系统的安全已成为越来越重要的任务。通过遵从这些最佳实践,可以帮助减少 DB2 数据服务器受到的安全威胁。您应该将这些最佳实践与系统架构中其他级别上的安全最佳实践和策略结合使用,以确保获得完善的安全解决方案。


相关主题

  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文
  • 下载 DB2 9 (test drive),亲自尝试本文介绍的特性。
  • DB2 9 在线信息中心:DB2 在线(可搜索)文档。
  • 了解用户和组帐户与 DB2 UDB 的交互”(developerWorks,2005 年 8 月):这篇文章描述了安装和使用 IBM DB2 Universal Database for Linux、UNIX and Windows,Version 8.2 所需的不同用户和组账户。它还介绍了 DB2 UDB 安全模型,包括用户身份验证、用户和组授权和超级用户。
  • 理解 DB2 Universal Database 安全性插件”(developerWorks,2005 年 12 月):了解关于 IBM DB2 Universal Database 安全插件的知识,这是 Version 8.2 中引入的新特性。这篇文章解释了安全插件的作用,并教您如何启用和编写自己的安全插件。
  • 理解在 DB2 UDB 中如何实现权限和特权”(developerWorks,2006 年 1 月):这篇文章讨论了 DB2 UDB 中不同的管理权限级别和特权,以及如何将权限授给用户和组账户,如何撤销用户和组账户的权限。
  • 理解 DB2 审计功能”(developerWorks,2006 年 3 月):了解 DB2 审计功能和它的作用,学习如何通过 db2audit 命令使用和配置它,并获得关于有效使用它的提示。
  • developerWorks Information Management 专区: 这里可以找到更多适合 DB2 for Linux、UNIX 和 Windows 开发人员和管理员的参考资料。

评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=158747
ArticleTitle=DB2 安全性,第 8 部分: 数据库安全的 12 条军规
publish-date=09112006