20.2. 认证方法

下面的小节更详细地描述认证方法。

20.2.1. 信任认证

如果声明了 trust (信任)认证模式, PostgreSQL 就假设任何可以联接到服务器的人都可以以任何他声明的数据库用户名(包括超级用户)连接。 当然,在 databaseuser 字段里面的限制仍然适用。 这个方法应该用于那些在联接到服务器已经有足够操作系统层次保护的环境里。

trust 认证对于单用户工作站的本地联接是非常合适和方便的。 通常它本身并适用于多用户环境的机器。 不过,即使在多用户的机器上,你也可以使用 trust, 只要你利用文件系统权限限制了对服务器的 Unix 域套接字文件的访问。 要做这些限制,你可以设置 参数 unix_socket_permissions (以及可能还有 unix_socket_group),就象 Section 17.3 里描述的那样。 或者你可以设置 unix_socket_directory,把Unix 域套接字文件放在一个经过恰当限制的目录里。

设置文件系统权限只能帮助 Unix 套接字联接。它不会限制本地 TCP/IP 联接; 因此,如果你想利用文件系统权限来控制本地安全,那么删除 pg_hba.conf 里的 host ... 127.0.0.1 ... 行,或者把它改为一个非 trust 的认证方法。

trust 认证模式只适合 TCP/IP 连接,只有在你信任那些在 pg_hba.conf 里声明为 trust,允许联接到服务器的行上的所有机器上面的所有用户的时候才是合适的。 很少有理由使用 trust 作为任何除来自localhost(127.0.0.1)以外的 TCP/IP 联接的认证方式。

20.2.2. 口令认证

以口令为基础的认证方法包括 md5crypt, 和 password。这些方法操作上非常类似,只不过口令通过联接传送的方法不同: 分别是,MD5散列,crypt 加密,明文。 一个限制是,crypt 不能使用加密了存储在 pg_authid 里的口令。

如果你担心口令被窃听("sniffing"), 那么 md5 比较合适,只有在你必需支持 7.2 以前的老的客户端的时候, 才需要选 crypt。如果我们在开放的互联网上使用, 应该尽可能避免使用 password(除非你在联接上使用了 SSL, SSH,或者其他通讯安全的联接封装。)

PostgreSQL 数据库口令与任何操作系统用户口令无关。 各个数据库用户的口令是存储在pg_authid系统表里面的。 口令可以用 SQL 语言命令 CREATE USERALTER USER 等管理,也就是说, CREATE USER foo WITH PASSWORD 'secret';。缺省时,如果没有明确地设置口令,存储的口令是空并且该用户的口令认证总会失败。

要限制允许访问某数据库的用户集, 可以在 pg_hba.conf 中的 user 字段列出这些用户,就像前面的小节解释的那样。

20.2.3. Kerberos 认证

Kerberos 是一种适用于在公共网络上进行分布计算的工业标准的安全认证系统。 对 Kerberos 系统的叙述远远的超出了本文档的范围; 总的说来它是相当复杂(同样也相当强大)的系统。 Kerberos FAQMIT 雅典娜计划 是个开始学习的好地方。 现存在好几种Kerberos发布的源代码。

PostgreSQL 支持 Kerberos 5, Kerberos 支持必须在制作的时候打开。参阅 Chapter 14 获取更多信息。

PostgreSQL 运行时象一个普通的 Kerberos 服务。 服务主的名字是 servicename/hostname@realm

servicename 可以用 krb_srvname 配置参数在服务器端设置, 或者在客户端使用 krbsrvname 连接参数设置。 (又见 Section 28.1。) 制作的时候,可以把安装时的缺省 postgres 修改掉,方法是使用 ./configure --with-krb-srvnam=whatever hostname。 在大多数情况下,我们不需要修改这个参数。但是,如果需要在同一台主机上同时安装多套 PostgreSQL, 那么这个就是必须的了。 有些 Kerberos 实现还可能要求其它的服务名,比如,Microsoft Active Directory 就要求服务名必须是大写的 (POSTGRES)。

客户主自给必须用它们自己的 PostgreSQL 用户名作为第一个部件, 比如 pgusername/otherstuff@realm。 目前 PostgreSQL 没有检查客户的域; 因此如果你打开了跨域的认证,那么在任意域里任何可以和你通讯的主都会被接受。

确认你的服务器的密钥表文件是可以被 PostgreSQL 服务器帐户读取(最好就是只读的)(又见 Section 16.1)。 密钥文件( keytab)的位置是用配置参数 krb_server_keyfile 声明的。 缺省是 /usr/local/pgsql/etc/krb5.keytab (或者任何在制作的时候声明为 sysconfdir 的目录。)

密钥表文件(keytab)是在 Kerberos 软件里生成的,参阅 Kerberos 文档获取细节。 下面的例子是可以用于 MIT 兼容的 Kerberos 5 实现:

kadmin% ank -randkey postgres/server.my.domain.org
kadmin% ktadd -k krb5.keytab postgres/server.my.domain.org

阅读 Kerberos 的文档获取详细信息。

在和数据库联接的时候,请确保自己对每个主都拥有一张匹配所请求的数据库用户名的门票。 比如,对于数据库用户 fred,主 fred@EXAMPLE.COMfred/users.example.com@EXAMPLE.COM 都可以用于与数据库服务器认证。

如果你在你的Apache apache web 服务器上使用了mod_auth_kerbmod_perl, 你可以用一个mod_perl脚本进行 AuthType KerberosV5SaveCredentials。 这样就有了一个通过 web 的安全数据库访问,不需要额外的口令。

20.2.4. 基于 Ident 的认证

身份(ident)认证方法的运做模式是通过获取客户端的操作系统用户名, 然后使用一个列出许可的系统用户和对应的数据库用户对应关系的映射文件, 判断对应许可的数据库用户名之方法来认证。 判断客户端的用户名是非常关键的安全点,根据连接类型的不同,它的实现方法也略有不同。

20.2.4.1. 透过 TCP/IP 的身份认证

"Identification Protocol(标识协议)"RFC 1413 里面描述。实际上每个类Unix的操作系统都带着一个缺省时侦听113端口的身份服务器。 身份服务器的基本功能是回答类似这样的问题: "是什么用户从你的端口X初始化出来联接到我的端口Y上来了?"。 因为在建立起物理联接后,PostgreSQL 既知道 X 也知道 Y, 因此它可以询问运行尝试联接的客户端的主机,并且理论上可以用这个方法判断发起联接的操作系统用户。

这样做的缺点是它取决于客户端的完整性:如果客户端不可信或者被攻击者攻破, 而且它们可以在113端口上运行任何程序并且返回他们选择的任何用户的话,就无法认证了。 因此这个认证方法只适用于封闭的网络, 这样的网络里的每台客户机都处于严密的控制下并且数据库和操作系统管理员可以比较方便地联系上。 换句话说,你必须信任运行身份(ident)服务的机器。下面是警告:

 

身份标识协议并不适用于认证或者访问控制协议。

 
--RFC 1413 

有些身份服务器有一个非标准的选项,导致返回的用户名是加密的, 使用的是只有原机器的管理员知道的一个密钥。在与 PostgreSQL 配合使用身份认证的时候, 你一定不能使用这个选项,因为 PostgreSQL 没有任何方法对返回的字串进行解密以获取实际的用户名。

20.2.4.2. 透过本地套接字的身份认证

在支持用于 Unix 域套接字的SO_PEERCRED请求的系统上, (目前是 LinuxFreeBSDNetBSDOpenBSDBSD/OS), 身份认证也可以用于局部联接。这个时候,使用身份认证不会增加安全风险; 实际上这也是在这种系统上使用本地联接时的优选方法。

在没有 SO_PEERCRED 请求的系统上,身份认证只能通过TCP/IP连接获取。 如果需要绕开这个限制,我们可以声明 localhost 地址 127.0.0.1,然后让连接指向这个地址。 这个方法适用于你相信本机身份认证服务器的场合。

20.2.4.3. Ident 映射

当使用以身份为基础的认证时,在判断了初始化联接的操作系统用户的名字后, PostgreSQL 判断他是否可以以他所请求的数据库用户的身份联接。 这个判断是由跟在pg_hba.conf 文件里的 ident 关键字后面的身份映射控制的。 有一个预定义的身份映射是sameuser,表示任何操作系统用户都可以以同名数据库用户进行联接 (如果后者存在的话)。其他映射必须手工创建。

sameuser 的身份映射定义在身份映射文件里, 其名字缺省是 pg_ident.conf, 并且缺省存放在集群的数据目录里。 (不过,我们可以把映射文件放在其它地方,参阅 ident_file 配置参数。) 身份映射文件包含下面通用的格式:

map-name ident-username database-username

注释和空白和 pg_hba.conf 文件里的一样处理。map-name 是将用于在pg_hba.conf里引用这个映射的任意名称。 另外两个域声明某个操作系统用户被允许以哪个数据库用户的身份进行联接。 同一个map-name 可以重复用于在一个映射里声明更多的用户映射。 对一个操作系统用户可以映射为多少个数据库用户没有限制,反之亦然。

在系统启动和主服务器( postmaster )收到一个 SIGHUP 信号的时候会读取 pg_ident.conf 文件。如果你在一台活跃的系统上编辑该文件, 那么你需要给 postmaster 发信号(用 pg_ctl reload 或者 kill -HUP 令其重新读取该文件。)

Example 20-2里是一个可以和在 Example 20-1 里面演示的pg_hba.conf文件配合使用的 pg_ident.conf 文件。 在这个例子的设置里,任何登录到 192.168 网络里的机器的用户,如果用户名不是 bryanhann,或 robert就不能获准访问。 Unix 用户robert只有在试图以PostgreSQL用户 bob身份联接时才允许访问,而不能是 robert 或其他什么身份。 ann 将只允许以ann的身份联接。 用户bryanh允许以他自己的 bryanh 身份或者做为 guest1 进行联接。

Example 20-2. 一个 pg_ident.conf 文件例子

# MAPNAME     IDENT-USERNAME    PG-USERNAME

omicron       bryanh            bryanh
omicron       ann               ann
# bob 在这台机器上的用户名是 robert
omicron       robert            bob
# bryanh 也可以以 guest1 身份连接
omicron       bryanh            guest1

20.2.5. PAM 认证

这个认证方法操作起来类似 password, 只不过它使用 PAM(Pluggable Authentication Modules)作为认证机制。 缺省的 PAM 服务名是 postgresql。 你可以在文件 pg_hba.confpam 关键字后面提供自己的可选服务名。 PAM 只用于验证用户名/口令对。因此,在使用 PAM 进行认证之前,用户必须已经存在于数据库里。 有关 PAM 的更多信息,请阅读 Linux-PAM页面 Solaris PAM 页面