下面的小节更详细地描述认证方法。
如果声明了 trust 认证模式,PostgreSQL 就假设任何可以连接到服务器的人都可以以任何他声明的数据库用户名(包括超级用户)连接。当然,在 database 和 user 字段里面的限制仍然适用。这个方法应该用于那些在连接到服务器已经有足够操作系统层次保护的环境里。
trust 认证对于单用户工作站的本地连接是非常合适和方便的。通常它本身并不适用于多用户环境的机器。不过,即使在多用户的机器上,你也可以使用 trust ,只要你利用文件系统权限限制了对服务器的 Unix 域套接字文件的访问。要做这些限制,你可以设置 unix_socket_permissions 参数(以及可能还有 unix_socket_group),就像节17.3里描述的那样。或者你可以设置 unix_socket_directory ,把 Unix 域套接字文件放在一个经过恰当限制的目录里。
设置文件系统权限只能帮助 Unix 套接字连接,它不会限制本地 TCP/IP 连接。因此,如果你想利用文件系统权限来控制本地安全,那么删除 pg_hba.conf 文件中的 host ... 127.0.0.1 ... 行,或者把它改为一个非 trust 的认证方法。
trust 认证模式只适合 TCP/IP 连接,只有在你信任那些 trust 行上所有机器中的所有用户的时候才是合适的。很少有理由使用 trust 作为任何除来自 localhost(127.0.0.1) 以外的 TCP/IP 连接的认证方式。
以口令为基础的认证方法包括 md5, crypt, password 。这些方法操作上非常类似,只不过口令通过连接传送的方法不同:MD5 散列、crypt 加密、明文。一个限制是 crypt 不能使用存储在 pg_authid 中已加密的口令。
如果你担心口令被窃听,那么 md5 比较合适,只有在你必需支持 7.2 以前的老的客户端的时候,才需要选 crypt 。如果我们在开放的互联网上使用,应该尽可能避免使用 password(除非你在连接上使用了 SSL/SSH 或其它通讯安全的连接封装)。
PostgreSQL 数据库口令与任何操作系统用户口令无关。各个数据库用户的口令是存储在 pg_authid 系统表里面。口令可以用 SQL 语言命令 CREATE USER 和 ALTER USER 等管理(比如 CREATE USER foo WITH PASSWORD 'secret'; 。缺省时,如果没有明确设置口令,那么存储的口令是空并且该用户的口令认证总会失败。
Kerberos 是一种适用于在公共网络上进行分布计算的工业标准的安全认证系统。对 Kerberos 系统的叙述远远超出了本文档的范围;总的说来它是相当复杂(同样也相当强大)的系统。Kerberos FAQ 或 MIT Kerberos page 是个开始学习的好地方。现存在好几种 Kerberos 发布的源代码。Kerberos 只提供安全认证,但并不加密在网络上传输的查询和数据,SSL 可以用于这个目的。
PostgreSQL 支持 Kerberos 5 ,Kerberos 支持必须在编译的时候打开。参阅章14获取更多信息。
PostgreSQL 运行时像一个普通的 Kerberos 服务。服务主的名字是 servicename/hostname@realm 。
servicename 可以用 krb_srvname 配置参数在服务器端设置,或者在客户端使用 krbsrvname 连接参数设置(又见节29.1)。编译的时候,可以把安装时的缺省 postgres 修改掉,方法是使用 ./configure --with-krb-srvnam=whatever 。在大多数情况下,我们不需要修改这个参数。但是,如果需要在同一台主机上同时安装多套 PostgreSQL ,那么这个就是必须的了。有些 Kerberos 实现还可能要求其它的服务名,比如 Microsoft Active Directory 就要求服务名必须是大写的(POSTGRES)。
hostname 是服务器的全限定主机名。服务主的领域就是主机的首选领域。
客户主自己必须用它们自己的 PostgreSQL 用户名作为第一个部件,比如 pgusername/otherstuff@realm 。目前 PostgreSQL 没有检查客户的域;因此如果你打开了跨域的认证,那么在任意域里任何可以和你通讯的主都会被接受。
确认服务器的密钥表文件是可以被 PostgreSQL 服务器帐户读取(最好就是只读的)(又见节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
在和数据库连接的时候,请确保自己对每个主都拥有一张匹配所请求的数据库用户名的门票。比如,对于数据库用户 fred ,主 fred@EXAMPLE.COM 和 fred/users.example.com@EXAMPLE.COM 都可以用于与数据库服务器认证。
如果你在 Apache 服务器上使用了 mod_auth_kerb 和 mod_perl 模块,你可以用一个 mod_perl 脚本进行 AuthType KerberosV5SaveCredentials 。这样就有了一个通过 web 的安全数据库访问,不需要额外的口令。
ident 认证方法是通过获取客户端的操作系统用户名,然后使用一个记录了系统用户与数据库用户对应关系的映射文件,判断对应许可的数据库用户名的方法来认证。判断客户端的用户名是非常关键的安全点,根据连接类型的不同,它的实现方法也略有不同。
"Identification Protocol"(标识协议)在 RFC 1413 里面描述。实际上每个类 Unix 的操作系统都带着一个缺省时侦听 113 端口的身份服务器。身份服务器的基本功能是回答类似这样的问题: "是什么用户从你的端口 X 初始化出来连接到我的端口 Y 上来了?" 。因为在建立起物理连接后,PostgreSQL 既知道 X 也知道 Y ,因此它可以询问运行尝试连接的客户端的主机,并且理论上可以用这个方法判断发起连接的操作系统用户。
这样做的缺点是它取决于客户端的完整性:如果客户端不可信或者被攻击者攻破,而且它们可以在 113 端口上运行任何程序并且返回他们选择的任何用户的话,就无法认证了。因此这个认证方法只适用于封闭的网络,这样的网络里的每台客户机都处于严密的控制下并且数据库和操作系统管理员可以比较方便地联系上。换句话说,你必须信任运行身份(ident)服务的机器。下面是警告:
身份标识协议并不适用于认证或者访问控制协议。 | ||
--RFC 1413 |
有些身份服务器有一个非标准的选项,导致返回的用户名是加密的,使用的是只有原机器的管理员知道的一个密钥。在与 PostgreSQL 配合使用身份认证的时候,你一定不能使用这个选项,因为 PostgreSQL 没有任何方法对返回的字符串进行解密以获取实际的用户名。
在支持用于 Unix 域套接字的 SO_PEERCRED 请求的系统上(Linux, FreeBSD, NetBSD, OpenBSD, BSD/OS),身份认证也可以用于局部连接。这个时候,使用身份认证不会增加安全风险;实际上这也是在这种系统上使用本地连接时的首选方法。
在没有 SO_PEERCRED 求的系统上,身份认证只能通过 TCP/IP 连接获取。如果需要绕开这个限制,我们可以声明 localhost 地址 127.0.0.1 ,然后让连接指向这个地址。这个方法适用于你信任本机身份认证服务器的场合。
当使用以身份为基础的认证时,在判断了初始化连接的操作系统用户名后,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 可以重复用于在一个映射里声明更多的用户映射。对一个操作系统用户可以映射为多少个数据库用户没有限制,反之亦然。
在系统启动和主服务器收到一个 SIGHUP 信号的时候会读取 pg_ident.conf 文件。如果你在一台活跃的系统上编辑该文件,那么你需要给主服务器发信号(使用 pg_ctl reload 或 kill -HUP)令其重新读取该文件。
例20-1里是一个可以和在例20-2里面演示的 pg_ident.conf 文件配合使用的 pg_hba.conf 文件。在这个例子的设置里,任何登录到 192.168 网络里的机器的用户,如果用户名不是 bryanh, ann, robert 就不能获准访问。Unix 用户 robert 只有在试图以 PostgreSQL 用户 bob 身份连接时才允许访问,而不能是 robert 或其它什么身份。ann 将只允许以 ann 的身份连接。用户 bryanh 允许以他自己的 bryanh 身份或者作为 guest1 进行连接。
这个认证方法操作起来类似 password ,只不过它使用 LDAP 作为认证机制。LDAP 只用于验证用户名/口令对。因此,在使用 LDAP 进行认证之前,用户必须已经存在于数据库里。你可以在 pg_hba.conf 文件的 ldap 关键字后面提供自己的可选服务名。该参数的格式如下:
ldap[s]://servername[:port]/base dn[;prefix[;suffix]]
例如:
ldap://ldap.example.net/dc=example,dc=net;EXAMPLE\
如果指定了 ldaps 而不是 ldap ,那么将使用 TLS 加密连接。需要注意的是这仅仅加密 PostgreSQL 服务器与 LDAP 服务器之间的连接。客户端与 PostgreSQL 服务器之间并不受此影响。要使用 TLS 加密,你需要在配置 PostgreSQL 之前先配置好 LDAP 库。加密 LDAP 仅在平台的 LDAP 库支持的情况下才可用。
如果没有指定端口,将使用 LDAP 库默认的端口。
服务器将使用客户端提供的用户名绑定到 base dn 指定的识别名(Distinguished Name)上。如果指定了 prefix 和 suffix ,那么将在邦定之前被前缀/后缀到用户名上。通常前缀参数用于在活动目录环境中指定 cn=, DOMAIN\ 。
这个认证方法操作起来类似 password ,只不过它使用 PAM 作为认证机制。缺省的 PAM 服务名是 postgresql 。你可以在 pg_hba.conf 文件的 pam 关键字后面提供自己的可选服务名。PAM 只用于验证用户名/口令对。因此,在使用 PAM 进行认证之前,用户必须已经存在于数据库里。有关 PAM 的更多信息,请阅读 Linux-PAM 页面 和 Solaris PAM 页面。