本系列的 第 2 部分 介绍了 DB2 安全性插件、实现 DB2 安全性的方法及一系列与安全性插件相关的详细信息。本系列的 第 6 部分 介绍了带有 Kerberos 安全性插件的 DB2 和如何使用该插件来部署 Kerberos 身份验证。本文阐述了将定制的安全性插件部署到 DB2 系统前,插件编写人员或数据库管理人员应该测试的内容。
DB2 中的授权是基于两方面内容的:
- 执行特定任务的外部用户的有效数据库授权 ID(authid)
- 该用户在特定组中的成员关系
在获知用户是否被授权进行特定操作之前,DB 2 必须能够获知外部用户的有效数据库授权 ID 及其所属的组。为了找到有效数据库授权 ID,需要确保外部用户就是所声称的用户,然后将其外部用户 ID 映射到内部 DB2 授权 ID。此过程被称为身份验证。DB2 没有用于维护用户 ID 和密码,或用户 ID 组成员关系的机制。
有两个事件需要使用(客户端或服务器端)身份验证插件或组成员查找插件:
- 连接或实例连接时
- 实例级操作授权时
实例级操作是涉及 DB2 实例维护的任何操作。实例级操作的典型例子为更新数据库管理器配置参数和启动数据库管理器。
首先,我们看一下实例级操作。大多数实例级操作命令不会接受用户 ID 或密码作为输入部分。在这种情况下,DB2 使用客户端身份验证插件(即 client auth 插件)找到发出命令的当前登录用户。(这就是所谓的获得默认登录上下文。登录上下文可以是用户 ID/密码对或 Generic Security Services API [GSS-API] 凭证,如 Kerberos 票据)。一旦获取用户的身份,将使用 DB2 组成员查找插件(即 group plug-in)为用户生成组授权 ID 列表。
在连接建立或实例连接中,用户 ID 和密码是可选的。如果用户选择不指定用户 ID 和密码,则 DB2 使用客户端身份验证插件来获得默认登录上下文。然后,将登录上下文发送到服务器以获取用户的组授权 ID。如果用户选择指定用户 ID 和密码,且未将身份验证类型数据库管理器配置参数指定为 CLIENT,则 DB2 执行下面的步骤:
表 1. 除 CLIENT 之外的身份验证的信息流
| 客户机 | 信息流(如果可用) | 服务器 |
|---|---|---|
| (客户端身份验证插件) 如果已实现 db2secRemapUserid 且身份验证插件是基于用户 ID/密码的,则重新映射用户 ID、密码和名称空间。请注意,该过程也适用于默认登录上下文情况。 | ||
| 发送登录上下文到服务器。 | 登录上下文 -> | 服务器接收了登录上下文。 |
| (服务器端身份验证插件) 验证登录上下文(验证用户 ID 和密码或 GSS-API 凭证,如 Kerberos 票据),并获取用户的授权 ID。 | ||
| 获取正在使用服务器上组成员查找插件的用户的组授权 ID。 |
如果在数据库服务器上将身份验证类型指定为 CLIENT 身份验证,则执行下面的步骤:
表 2. CLIENT 身份验证的信息流
| 客户机 | 信息流(如果可用) | 服务器 |
|---|---|---|
| (客户端身份验证插件) 如果已实现 db2secRemapUserid 且身份验证插件是基于用户 ID/密码的,则重新映射用户 ID、密码和名称空间。请注意,该过程也适用于默认登录上下文情况。 | ||
| (客户端身份验证插件) 验证登录上下文(验证用户 ID 和密码或 GSS-API 凭证,如 Kerberos 票据)。 | ||
| 发送用户 ID 到服务器。 | user ID -> | (服务器端身份验证插件) 服务器接收了用户 ID 并获取用户的授权 ID。 |
| 获取正在使用服务器上组成员查找插件的用户的组授权 ID。 |
基于前文所述的安全性插件职责,建议安全性插件至少应进行下面的测试:
- 使用未授权的用户,尝试执行实例级操作,如获得数据库管理器配置参数。此操作应该失败。
- 使用授权的用户,尝试执行实例级操作。此操作应该成功。
- 使用有效的用户 ID 和密码,建立数据库连接,并尝试使用授予其中一个组授权 ID 的特权。此操作应该成功。
- 尝试使用无效的用户 ID 或无效的密码进行连接。此操作应该失败。
- 尝试不指定用户 ID 和密码而进行连接。此操作仅当客户机和服务器处于同一个机器上时才能进行,且在定制的安全性插件中没有执行任何特殊的限制逻辑。这样确保定制的安全性插件将正确的登录用户凭证返回到 DB2。
- 如果正在实现定制的组成员查找插件,则请确保 db2secGetGroupForUser API 了解授权 ID,并且始终是大写的,无论定制的身份验证插件可能返回大小写混合或小写授权 ID。
安全性插件 loader 程序允许模拟 DB2 对上述建议测试的响应。这对于断定某个特定问题是由插件中的代码造成的,还是由 DB2 引起的是非常有用的。
程序输入为:
- -c option:客户端身份验证插件的全限定路径和插件名称。
- -s option:服务器端身份验证插件的全限定路径和插件名称。
- -g option:组成员查找插件的全限定路径和插件名称。
- -u option:用户 ID。
- -p option:密码。(对于 GSS-API 或 Kerberos,这是用于获得用户凭证的密码。)
- -d option:数据库名称。
- -n option:新密码。
- -a option:用户授权 ID。
启动或执行 loader 时,根据需要加入三个指定的安全性插件(客户端身份验证插件、服务器身份验证插件和组成员查找插件),并且确定身份验证插件类型(例如基于用户 ID/密码、基于 Kerberos 或基于 GSS-API)。调用每个插件的初始化函数,且检索每个插件的全部函数指针。
基于所指定的选项组合,将执行下面四个测试类型。
为了简单起见,该 loader 不支持客户端身份验证测试,且不为定制的插件(例如 db2secGetConDetails)提供 get Client connection details 回调函数。为插件提供了 db2secLogMessage,但输出直接到达标准输出(屏幕)。
这个 loader 提供了下面四个测试功能,用来模拟安全性插件在 DB2 环境中调用序列完全相同的 API 的用法。
用给定的用户 ID 和密码建立连接,且验证密码或凭据。输出是 authid 和组 authid 列表。
- 如果正在使用 Kerberos 或基于 GSS-API 的身份验证插件,则 API 调用序列如下:
- 客户机插件:db2secProcessServerPrincipalName
- 客户机插件:db2secGenerateInitialCred
- 客户机插件:gss_init_sec_context
- 服务器插件:gss_accept_sec_context
在客户端 API:gss_init_sec_context 与服务器端 API:gss_accept_sec_context 之间进行循环,直到其中一端返回 GSS_S_COMPLETE 为止。如果希望从另一端得到更多令牌,则 API 应返回 GSS_S_CONTINUE_NEEDED。
- 客户机插件:gss_release_buffer、gss_release_name、gss_release_cred、db2secFreeInitInfo、gss_delete_sec_context
- 服务器插件:ss_release_buffer、db2secGetAuthIDs
- 组插件:db2secGetGroupForUser
- 客户机插件:db2secFreeToken
- 服务器插件:gss_delete_sec_context
- 组插件:db2secFreeGroupListMemory
图 1. 使用 Kerberos 或基于 GSS-API 的身份验证插件的 API 调用序列
- 如果正在使用基于用户 ID/密码的身份验证插件,则 API 调用序列如下:
- 客户机插件:db2secRemapUserid(如果它是可选实现的)
- 服务器插件:db2secValidatePassword、db2secGetAuthIDs
- 组插件:db2secGetGroupForUser
- 服务器插件:db2secFreeToken
- 组插件:db2secFreeGroupListMemory
图 2. 使用基于用户 ID/密码的身份验证插件的 API 调用序列
不提供用户 ID 和密码(默认的登录上下文)而建立连接。输出是 authid 和组 authid 列表。
- 如果正在使用 Kerberos 或基于 GSS-API 的身份验证插件,则 API 调用序列如下:
- 客户机插件:db2secGetDefaultLoginContext
- 客户机插件:db2secProcessServerPrincipalName
- 客户机插件:gss_init_sec_context
- 服务器插件:gss_accept_sec_context
在客户端 API:gss_init_sec_context 和服务器端 API:gss_accept_sec_context 之间进行循环,直到其中一端返回 GSS_S_COMPLETE 为止。如果希望从另一端得到更多令牌,则 API 应返回 GSS_S_CONTINUE_NEEDED。
- 客户机插件:gss_release_buffer、gss_release_name、gss_delete_sec_context
- 服务器插件:gss_release_buffer、db2secGetAuthIDs
- 组插件:db2secGetGroupForUser
- 客户机插件:db2secFreeToken
- 服务器插件:gss_delete_sec_context
- 组插件:db2secFreeGroupListMemory
图 3. 使用 Kerberos 或基于 GSS-API 的身份验证插件的 API 调用序列
- 如果正在使用基于用户 ID/密码的身份验证插件,则 API 调用序列如下:
- 客户机插件:db2secGetDefaultLoginContext、db2secFreeToken
- 服务器插件:db2secGetAuthIDs
- 组插件:db2secGetGroupForUser
- 服务器插件:db2secFreeToken
- 组插件:db2secFreeGroupListMemory
图 4. 使用基于用户 ID/密码的身份验证插件的 API 调用序列
给定用户授权 ID,输出是组 authid 列表。
API 调用序列如下:
- 组插件:db2secGetGroupsForUser
图 5. API 调用序列
模拟实例级操作(没有用户 ID 和密码)的本地授权测试。输出是组 authid 列表。
API 调用序列如下:
- 客户机插件:db2secGetDefaultLoginContext
- 组插件:db2secGetGroupForUser
- 客户机插件:db2secFreeToken
- 组插件:db2secFreeGroupListMemory
图 6. API 调用序列
DB2 9 中对 DB2 安全性插件基础设施进行了很多增强,包括基于轻量级目录访问协议(Lightweight Directory Access Protocol,LDAP)的身份验证插件的输送、基于 LDAP 的组成员查找插件的输送、及 client connection details 的增强以包括对 TCP/IP 版本 6 和客户机操作系统平台信息的支持。
可以从 DB2 LDAP 验证插件 下载受 IBM 支持的基于 LDAP 的身份验证插件和组成员查找插件。
如果已经通过 TCP/IP 地址实现了连接限定(在本系列 第 2 部分 的 “测试插件连接限定能力的步骤” 一节中可以找到如何进行操作的示例),且您的公司正准备实现 TCP/IP 版本 6,则需要修改安全性插件,从而进行对应的操作。
首先,需要从使用下面所列的版本 2 或 3 的连接详细信息结构(节选自 IBM 发布的头文件 db2secPlugin.h)开始。版本 2 和 3 的区别在于版本 3 还给出了客户机操作系统平台。
清单 1. 客户机连接详细信息结构的新版本
typedef struct db2sec_con_details_2
{
db2int32 clientProtocol; /* See SQL_PROTOCOL_ in sqlenv.h */
db2Uint32 clientIPAddress; /* Set if protocol is TCPIP4 */
db2Uint32 connect_info_bitmap;
db2int32 dbnameLen;
char dbname[DB2SEC_MAX_DBNAME_LENGTH + 1];
db2Uint32 clientIP6Address[4];/* Set if protocol is TCPIP6 */
} db2sec_con_details_2;
typedef struct db2sec_con_details_3
{
db2int32 clientProtocol; /* See SQL_PROTOCOL_ in sqlenv.h */
db2Uint32 clientIPAddress; /* Set if protocol is TCPIP4 */
db2Uint32 connect_info_bitmap;
db2int32 dbnameLen;
char dbname[DB2SEC_MAX_DBNAME_LENGTH + 1];
db2Uint32 clientIP6Address[4];/* Set if protocol is TCPIP6 */
db2Uint32 clientPlatform; /* SQLM_PLATFORM_* from sqlmon.h */
db2Uint32 _reserved[16];
} db2sec_con_details_3;
|
然后,在调用回调函数时,使用 DB2SEC_CON_DETAILS_VERSION_2 或 DB2SEC_CON_DETAILS_VERSION_3 来代替 DB2 V8.2 文档所建议的 DB2SEC_API_VERSION_1 或数字 1。例如,假定要使用连接详细信息版本 3;可以在插件中进行下面的回调:
struct db2sec_con_details_3 con_struct3;
rc = (getConDetails_fn)(DB2SEC_CON_DETAILS_VERSION_3, &con_struct3);
|
由于在整个机构上使用 TCP/IP 版本 6 是一个较长的过程,因此 DB2 可能会遇到一些仍使用 TCP/IP 版本 4 的客户机或其他切换到 TCP/IP 版本 6 的客户机。为了帮助使用者区分客户机,结构中 clientProtocol 字段现在可以返回 SQL_PROTOCOL_TCPIP4 或 SQL_PROTOCOL_TCPIP6,用来指示客户机正在使用的 TCP/IP 协议是版本 4,还是版本 6。
如果需要找到客户机的操作系统,则可以检查 DB2 通过回调函数返回到字段 clientPlatform 中的整数。整数到相应平台的映射如下(节选自 IBM 发布的头文件 sqlmon.h):
#define SQLM_PLATFORM_UNKNOWN 0 /* Unknown platform */ #define SQLM_PLATFORM_OS2 1 /* OS/2 */ #define SQLM_PLATFORM_DOS 2 /* DOS */ #define SQLM_PLATFORM_WINDOWS 3 /* Windows */ #define SQLM_PLATFORM_AIX 4 /* AIX */ #define SQLM_PLATFORM_NT 5 /* NT */ #define SQLM_PLATFORM_HP 6 /* HP */ #define SQLM_PLATFORM_SUN 7 /* Sun */ #define SQLM_PLATFORM_MVS_DRDA 8 /* MVS (client via DRDA) */ #define SQLM_PLATFORM_AS400_DRDA 9 /* AS400 (client via DRDA) */ #define SQLM_PLATFORM_VM_DRDA 10 /* VM (client via DRDA) */ #define SQLM_PLATFORM_VSE_DRDA 11 /* VSE (client via DRDA) */ #define SQLM_PLATFORM_UNKNOWN_DRDA 12 /* Unknown DRDA Client */ #define SQLM_PLATFORM_SNI 13 /* Siemens Nixdorf */ #define SQLM_PLATFORM_MAC 14 /* Macintosh Client */ #define SQLM_PLATFORM_WINDOWS95 15 /* Windows 95 */ #define SQLM_PLATFORM_SCO 16 /* SCO */ #define SQLM_PLATFORM_SGI 17 /* Silicon Graphic */ #define SQLM_PLATFORM_LINUX 18 /* Linux */ #define SQLM_PLATFORM_DYNIX 19 /* DYNIX/ptx */ #define SQLM_PLATFORM_AIX64 20 /* AIX 64 bit */ #define SQLM_PLATFORM_SUN64 21 /* Sun 64 bit */ #define SQLM_PLATFORM_HP64 22 /* HP 64 bit */ #define SQLM_PLATFORM_NT64 23 /* NT 64 bit */ #define SQLM_PLATFORM_LINUX390 24 /* Linux for S/390 */ #define SQLM_PLATFORM_LINUXZ64 25 /* Linux for z900 */ #define SQLM_PLATFORM_LINUXIA64 26 /* Linux for IA64 */ #define SQLM_PLATFORM_LINUXPPC 27 /* Linux for PPC */ #define SQLM_PLATFORM_LINUXPPC64 28 /* Linux for PPC64 */ #define SQLM_PLATFORM_OS390 29 /* OS/390 Tools (CC, DW) */ #define SQLM_PLATFORM_LINUXX8664 30 /* Linux for x86-64 */ #define SQLM_PLATFORM_HPIA 31 /* HP-UX Itanium 32bit */ #define SQLM_PLATFORM_HPIA64 32 /* HP-UX Itanium 64bit */ |
在本系列 第 2 部分 的示例连接限定代码中,gethostname 和 gethostbyname 用于数据库服务器的 TCP/IP 地址。下面是示例代码片断,其中阻塞了数据库服务器上的回路连接:
清单 2. 来自本系列第 2 部分的连接限定代码
/* If the connection is not local */
if (!(con_struct.connect_info_bitmap & DB2SEC_CONNECTION_ISLOCAL))
{
struct hostent* hostinfo;
char hostname[256];
int* firstaddr;
/* Get the address of the machine restricted */
gethostname(hostname, sizeof(hostname));
hostinfo = gethostbyname(hostname);
firstaddr = (int *)*(hostinfo->h_addr_list);
/* If the client IP address is the restricted one */
if (*firstaddr == con_struct.clientIPAddress)
{
/* We won't allow behavoir to connect through this IP address */
if (0 == strcmp(userid, "beauvoir"))
return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
}
}
|
为了使用 TCP/IP 版本 6,需要修改为以下代码:
清单 3. 使用 IP V6 的连接限定代码
if (!(con_struct3.connect_info_bitmap & DB2SEC_CONNECTION_ISLOCAL))
{
struct addrinfo* pAddr;
/* find the local IP address to compare it with the one retrieved */
if ((con_struct3.clientProtocol == SQL_PROTOCOL_TCPIP6) &&
(IN6_IS_ADDR_V4MAPPED((struct in6_addr *)con_struct3.clientIP6Address)))
{
/* Comment out the following line of code if your database server is not */
/* running on MS Windows */
aiHints.ai_flags = AI_ALL | AI_V4MAPPED;
}
else
{
aiHints.ai_flags = AI_PASSIVE;
}
aiHints.ai_family = (con_struct3.clientProtocol == SQL_PROTOCOL_TCPIP6)?
AF_INET6 : AF_INET;
aiHints.ai_socktype = SOCK_STREAM;
aiHints.ai_protocol = IPPROTO_TCP;
err = getaddrinfo(hostname, NULL, &aiHints, &aiList);
if (err)
{
Print("getaddrinfo error: %d\n", err);
return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
}
/* compare the IPs */
if (SQL_PROTOCOL_TCPIP6 == con_struct3.clientProtocol)
{
pAddr = aiList;
while (pAddr)
{
struct sockaddr_in6* s = (struct sockaddr_in6*)pAddr->ai_addr;
struct in6_addr *src = (struct in6_addr*)&s->sin6_addr;
struct in6_addr *dst =
(struct in6_addr*)&con_struct3.clientIP6Address;
/* check if address verified is the same format as the address
* sent by the client: compare only IPv6 format address with
* IPv6 ones or IPv6 mapped IPv4 with the same type */
if ((*(db2Uint32*)(&s->sin6_addr.s6_addr[0]) ==
con_struct3.clientIP6Address[0]) &&
(*(db2Uint32*)(&s->sin6_addr.s6_addr[4]) ==
con_struct3.clientIP6Address[1]) &&
(*(db2Uint32*)(&s->sin6_addr.s6_addr[8]) ==
con_struct3.clientIP6Address[2]) &&
(*(db2Uint32*)(&s->sin6_addr.s6_addr[12])==
con_struct3.clientIP6Address[3]))
{
/* don't allow beauvoir to connect through this ip address */
if (0 == strcmp(userid, "beauvoir"))
{
return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
}
else
{
break;
}
}
pAddr = pAddr->ai_next;
} /* while (pAddr) */
}
else /* This else clause is need if you have a mix v4 and v6 environment */
{
/* TCPIP4 */
struct sockaddr_in* s = (struct sockaddr_in*)aiList->ai_addr;
if (s->sin_addr.s_addr == con_struct3.clientIPAddress)
{
/* don't allow beauvoir to connect through this ip address */
if (0 == strcmp(userid, "beauvoir"))
return DB2SEC_PLUGIN_CONNECTION_DISALLOWED;
}
}
freeaddrinfo(aiList);
}
|
本文给出了 DB2 9 中 DB2 安全插件的增强信息,详细阐述了安全性插件的职责。本文还提出了基于这些职责的最小完备测试列表。现在您应知道如何使用安全性插件 loader 来测试定制的安全性插件,该 loader 可以在 下载 部分中找到。
| 描述 | 名字 | 大小 | 下载方法 |
|---|---|---|---|
| 插件 loader 程序 | loader.zip | 58KB | HTTP |
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
-
访问 developerWorks DB2 for Linux, UNIX, and Windows 参考资料页面,阅读文章和教程并连接其他参考资料,从而扩展您的 DB2 技能。
-
了解 DB2 Express-C,这是为社区提供的 DB2 Express Edition 免费版本。
-
随时关注 developerWorks 技术活动和网络广播。
-
developerWorks Information Management 专区:学习有关 DB2 的更多内容。查找技术文档、how-to 文章、培训、下载、产品信息和更多内容。
获得产品和技术
- DB2 LDAP 验证插件:下载受 IBM 支持的基于 LDAP 的身份验证插件和组成员查找插件。
-
下载 DB2 Enterprise 9 的免费试用版。
-
现在可以免费使用 DB2。下载 DB2 Express-C,这是为社区提供的 DB2 Express Edition 免费版本,提供与 DB2 Express Edition 相同的核心数据特性,为构建和部署应用程序提供了坚实的基础。
-
下载 IBM 产品的评估版,并获得应用程序开发工具及来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的中间件产品。
-
使用 IBM 试用软件 构建您的下一个开发项目,这些软件可直接从 developerWorks 下载。
讨论
- 参与论坛讨论。
-
通过参与 developerWorks
blog 加入 developerWorks 社区。
Kevin See, CISSP 是 IBM 多伦多实验室的一名专职软件开发人员,在 Kernel 小组从事 DB2 FVT 方面的工作。在此之前,他在 DB2 Security Development 小组和 DB2 SQL and Catalog Development 小组工作。他在 IBM 已经工作了 9 年,目前主要的工作范围是访问控制和身份验证模型。他拥有滑铁卢大学的数学(软件工程)硕士学位,同时还拥有阿卡迪亚大学的计算机科学学士学位。他是 IBM 认证的 XML 及相关技术解决方案开发人员,同时也是 DB2 认证的解决方案专家(DBA for OS/390、DBA for Linux/Unix/Windows 和 DB2 Family Application Development)。他还是 ISC2 认证的信息系统安全专家。