下列小节更详细地描述认证方法。
当trust
认证被指定时,PostgreSQL假设任何可以连接到服务器的人都被授权使用他们指定的任何数据库用户名(即使是超级用户)访问数据库。当然,在database
和 user
列中设置的限制仍然适用。只有当在操作系统层对进入服务器的连接有足够保护时,才应该使用这种方法。
trust
认证对于单用户工作站的本地连接是非常合适和方便的。通常它本身不适用于一台多用户机器。不过,只要你利用文件系统权限限制了对服务器的 Unix 域套接字文件的访问,即使在多用户机器上,你也可以使用trust
。 要做这些限制,你可以设置第 19.3 节中描述的unix_socket_permissions
配置参数(可能还有unix_socket_group
)。 或者你可以设置unix_socket_directories
配置参数来把 Unix 域套接字文件放在一个经过恰当限制的目录中。
设置文件系统权限只能有助于 Unix 套接字连接。本地 TCP/IP 连接不会被文件系统权限限制。因此,如果你想利用文件系统权限来控制本地安全,那么从pg_hba.conf
中移除host ... 127.0.0.1 ...
行,或者把它改为一个非trust
认证方法。
如果通过指定trust
的pg_hba.conf
行让你信任每一个被允许连接到服务器的机器上的用户,trust
认证只适合 TCP/IP 连接。为任何不是来自localhost(127.0.0.1)的 TCP/IP 连接使用trust
很少是合理的。
有几种基于口令的身份验证方法。这些方法的操作方式相似, 但在服务器上存储用户密码的方式以及客户端提供的密码如何通过连接发送方面有所不同。
scram-sha-256
如RFC 7677中所述, 方法scram-sha-256
执行SCRAM-SHA-256认证。这是一种挑战-响应架构, 可防止密码在不可信连接上嗅探,并支持以密码散列的形式将密码存储在服务器上, 这种形式被认为是安全的。
这是目前提供的方法中最安全的方法,但旧版客户端库不支持它。
md5
方法md5
使用自定义安全性较低的质询-响应机制。 它可以防止密码嗅探,并避免以纯文本形式将密码存储在服务器上, 但如果攻击者设法从服务器窃取密码哈希,则不提供保护。而且, MD5哈希算法现在不再被认为对于确定的攻击是安全的。
md5
方法不能使用db_user_namespace特性。
为了简化从md5
方法到新的SCRAM方法的转换, 如果在pg_hba.conf
中将md5
指定为方法,但服务器上用户的密码是SCRAM加密的(见下文), 那么自动选择基于SCRAM的认证。
password
The method password
sends the password in clear-text and is therefore vulnerable to password “sniffing” attacks. It should always be avoided if possible. If the connection is protected by SSL encryption then password
can be used safely, though. (Though SSL certificate authentication might be a better choice if one is depending on using SSL). 方法password
以明文形式发送密码,因此易受密码“嗅探” 攻击。如果可能,应始终避免使用它。不过如果连接受到SSL加密保护, 那么password
可以安全使用。(虽然如果使用SSL, SSL证书认证可能是更好的选择)。
PostgreSQL数据库口令独立于操作系统用户口令。每个数据库用户的口令被存储在pg_authid
系统目录中。口令可以用 SQL 命令CREATE USER和ALTER ROLE管理,例如CREATE USER foo WITH PASSWORD 'secret'
, 或者psql命令\password
。如果没有为一个用户设置口令,那么存储的口令为空并且对该用户的口令认证总会失败。
不同的基于密码的身份验证方法的可用性取决于用户的密码在服务器上是如何加密的 (或更准确地说是哈希)。这是在设置密码时由配置参数 password_encryption控制的。如果使用scram-sha-256
设置对密码进行了加密, 那么它可以用于身份验证方法scram-sha-256
和password
(但在后一种情况下密码传输将以纯文本形式)。如上所述, 认证方法规范md5
会自动切换到使用scram-sha-256
方法, 所以它也可以工作。如果密码是使用md5
设置加密的, 那么它只能用于md5
和password
认证方法规范 (同样,在后一种情况下用明文传输密码)。 (以前的PostgreSQL版本支持以纯文本格式在服务器上存储密码,这已不再可行。) 要查看当前存储的密码哈希值,请查看系统目录pg_authid
。
在确保所有正在使用的客户端库足够新以支持SCRAM后, 要将现有安装从md5
升级到scram-sha-256
, 在postgresql.conf
中设置 password_encryption = 'scram-sha-256'
, 让所有用户设置新密码,并将pg_hba.conf
中的认证方法声明更改为scram-sha-256
。
GSSAPI是用于 RFC 2743 中定义的安全认证的一个工业标准协议。PostgreSQL根据 RFC 1964 支持带Kerberos认证的GSSAPI。GSSAPI为支持它的系统提供自动认证(单点登录)。认证本身是安全的,但通过数据库连接发送的数据将不被加密,除非使用SSL。
当编译PostgreSQL时,GSSAPI 支持必须被启用,详见第 16 章。
当GSSAPI使用Kerberos时, 它会使用格式为
的标准 principal。 PostgreSQL服务器将接受该服务器所使用的 keytab 中包括的任何 principal,但是在从使用servicename
/hostname
@realm
krbsrvname
连接参数的客户端建立连接时要注意指定正确的 principal 细节(另见 第 33.1.2 节)。安装的默认值postgres
可以在编译时使用 ./configure --with-krb-srvnam=
其他值
修改。 在大部分的环境中,这个参数从不需要被更改。某些 Kerberos 实现可能要求一个不同的服务名, 例如 Microsoft Active Directory 要求服务名是大写形式(POSTGRES
)。
hostname
是服务器机器的被完全限定的主机名。服务 principal 的 realm 是该服务器机器的首选 realm。
客户端 principal 可以被通过pg_ident.conf
映射到不同的 PostgreSQL数据库用户名。例如, pgusername@realm
可能会被映射到pgusername
。 或者,你可以使用完整的username@realm
当事人作为PostgreSQL中的角色而无需任何映射。
PostgreSQL也支持一个参数把 realm 从 principal 中剥离。这种方法是为了向后兼容性,并且我们强烈反对使用它,因为这样就无法区分具有相同用户名却来自不同 realm 的不同用户了。要启用这种方法,可将include_realm
设置为 0。对于简单的单 realm 安装,这样做并且设置krb_realm
参数(这会检查 principal 的 realm 是否正好匹配krb_realm
中的参数)仍然是安全的。但比起在pg_ident.conf
中指定一个显式映射来说,这种方法的能力较低。
确认你的服务器的 keytab 文件是可以被PostgreSQL服务器帐 户读取的(最好是只读的) (又见第 18.1 节)。密钥文件的位置由配置 参数krb_server_keyfile指定。默认是/usr/local/pgsql/etc/krb5.keytab
(或者任何在编译的时候作为sysconfdir
的目录)。 出于安全原因,推荐对PostgreSQL服务器使用一个独立 的 keytab而不是开放系统 keytab 文件的权限。
keytab 文件由 Kerberos 软件生成,详见 Kerberos 文档。下面是 MIT 兼容的 Kerberos 5 实现的例子:
kadmin%
ank -randkey postgres/server.my.domain.orgkadmin%
ktadd -k krb5.keytab postgres/server.my.domain.org
当连接到数据库时,确保你有一个匹配被请求数据库用户名的 principal 的票据。例如,对于数据库用户名fred
,principal [email protected]
将能够连接。要也允许 principal fred/[email protected]
,可使用一个用户名映射,如第 20.2 节中所述。
下列被支持的配置选项用于GSSAPI:
include_realm
如果设置为 0,在通过用户名映射之前(第 20.2 节),来自已认证用户 principal 的 realm 名称会被剥离掉。我们不鼓励这样做,这种方法主要是为了向后兼容性而存在的,因为它在多 realm 环境中是不安全的(除非也使用 krb_realm
)。推荐用户让include_realm
设置为默认值(1)并且在pg_ident.conf
中提供一条显式的映射来把 principal 名称转换成PostgreSQL用户名。
map
允许在系统和数据库用户名之间的映射。详见第 20.2 节。 对于一个 GSSAPI/Kerberos 原则,例如[email protected]
(或者更不常见的username/[email protected]
), 用于映射的用户名会是[email protected]
(或者 username/[email protected]
,相应地),除非 include_realm
已经被设置为 0,在那种情况下 username
(或者username/hostbased
)是 映射时被视作系统用户名的东西。
krb_realm
设置 realm 为对用户 principal 名进行匹配的范围。 如果这个参数被设置,只有那个 realm 的用户将被接受。 如果它没有被设置,任何 realm 的用户都能连接,服从任何已完成的用户名映射。
SSPI是一种用于带单点登录的安全认证的Windows技术。 PostgreSQL在negotiate
模式中将使用 SSPI,它在可能的情况下使用Kerberos并在其他情况下自动降回到NTLM。只有在服务器和客户端都运行着Windows时,SSPI才能工作。或者在非 Windows 平台上GSSAPI可用时,SSPI也能工作。
当使用Kerberos认证时,SSPI和GSSAPI的工作方式相同,详见第 20.3.3 节。
下列被支持的配置选项用于SSPI:
include_realm
如果设置为 0,在通过用户名映射之前(第 20.2 节),来自已认证用户 principal 的 realm 名称会被剥离掉。我们不鼓励这样做,这种方法主要是为了向后兼容性而存在的,因为它在多 realm 环境中是不安全的(除非也使用krb_realm
)。推荐用户让 include_realm 设置为默认值(1)并且在pg_ident.conf
中提供一条显式的映射来把 principal 名称转换成PostgreSQL用户名。
compat_realm
如果被设置为 1,该域的 SAM 兼容名称(也被称为 NetBIOS 名称)被用于include_realm
选项。这是默认值。如果被设置为 0,会使用来自 Kerberos 用户主名的真实 realm 名称。
不要禁用这个选项,除非你的服务器运行在一个域账号(这包括一个域成员系统上的虚拟服务账号)下并且所有通过 SSPI 认证的所有客户端也在使用域账号,否则认证将会失败。
upn_username
如果这个选项和compat_realm
一起被启用,来自 Kerberos UPN 的用户名会被用于认证。如果它被禁用(默认),会使用 SAM 兼容的用户名。默认情况下,对于新用户账号这两种名称是一样的。
注意如果没有显式指定用户名,libpq会使用 SAM 兼容的名称。如果你使用的是libpq或者基于它的驱动,你应该让这个选项保持禁用或者在连接字符串中显式指定用户名。
map
允许在系统和数据库用户名之间的映射。详见第 20.2 节。 对于一个 GSSAPI/Kerberos 原则,例如[email protected]
(或者更不常见的username/[email protected]
), 用于映射的用户名会是[email protected]
(或者 username/[email protected]
,相应地),除非 include_realm
已经被设置为 0,在那种情况下 username
(或者username/hostbased
)是 映射时被视作系统用户名的东西。
krb_realm
设置领域为对用户 principal 名进行匹配的范围。如果这个参数被设置,只有那个领域的用户将被接受。如果它没有被设置,任何领域的用户都能连接,服从任何已完成的用户名映射。
ident 认证方法通过从一个 ident 服务器获得客户端的操作系统用户名并且用它作为被允许的数据库用户名(和可选的用户名映射)来工作。它只在 TCP/IP 连接上支持。
当为一个本地(非 TCP/IP)连接指定 ident 时,将实际使用 peer 认证(见第 20.3.6 节)。
下列被支持的配置选项用于ident:
map
允许系统和数据库用户名之间的映射。详见第 20.2 节。
“Identification Protocol(标识协议)”在 RFC 1413 中描述。实际上每个类 Unix 操作系统都带着一个默认监听 TCP 113 端口的 ident 服务器。ident 服务器的基本功能是回答类似这样的问题:“哪个用户从你的端口X
发起了连接并且连到了我的端口Y
?” 。因为当一个物理连接被建立后,PostgreSQL既知道X
也知道Y
, 所以它可以询问尝试连接的客户端主机上的 ident 服务器并且在理论上可以判断任意给定连接的操作系统用户。
这个过程的缺点是它依赖于客户端的完整性:如果客户端机器不可信或者被攻破,攻击者可能在 113 端口上运行任何程序并且返回他们选择的任何用户。因此这种认证方法只适用于封闭的网络, 这样的网络中的每台客户端机器都处于严密的控制下并且数据库和操作系统管理员操作时可以方便地联系。换句话说,你必须信任运行 ident 服务器的机器。注意这样的警告:
标识协议的本意不是作为一种认证或访问控制协议。 |
||
--RFC 1413 |
有些 ident 服务器有一个非标准的选项,它导致返回的用户名是被加密的,使用的是只有原机器管理员知道的一个密钥。当与PostgreSQL配合使用 ident 服务器时,一定不要使用这个选项,因为PostgreSQL没有任何方法对返回的字符串进行解密以获取实际的用户名。
Peer 认证方法通过从内核获得客户端的操作系统用户名并把它用作被允许的数据库用户名(和可选的用户名映射)来工作。这种方法只在本地连接上支持。
下列被支持的配置选项用于peer:
map
允许在系统和数据库用户名之间的映射。详见第 20.2 节。
Peer 认证只在提供getpeereid()
函数、SO_PEERCRED
套接字参数或相似机制的操作系统上可用。这些 OS 当前包括Linux、大部分的BSD包括macOS以及Solaris。
这种认证方法操作起来类似于password
, 只不过它使用 LDAP 作为密码验证方法。LDAP 只被用于验证用户名/口令对。因此,在使用 LDAP 进行认证之前,用户必须已经存在于数据库中。
LDAP 认证可以在两种模式下操作。在第一种模式中(我们将称之为简单绑定模式),服务器将绑定到构造成prefix
username
suffix
的可区分名称。通常,prefix
参数被用于指定 cn=
或者一个活动录环境中的DOMAIN
\
。suffix
被用来指定非活动目录环境中的DN的剩余部分。
在第二种模式中(我们将称之为搜索与绑定模式),服务器首先用一个固定的用户名和密码(用ldapbinddn
和ldapbindpasswd
指定)绑定到 LDAP 目录 ,并为试图登入该数据库的用户执行一次搜索。如果没有配置用户名和密码, 将尝试一次匿名绑定到目录。搜索将在位于ldapbasedn
的子树上被执行,并将尝试做一次ldapsearchattribute
中指定属性的精确匹配。一旦在这次搜索中找到用户,服务器断开并且作为这个用户重新绑定到目录,使用由客户端指定的口令来验证登录是正确的。这种模式与在其他软件中的 LDAP 认证所使用的相同,例如 Apache mod_authnz_ldap
和 pam_ldap
。这种方法允许位于目录中用户对象的更大灵活性,但是会导致建立两个到 LDAP 服务器的独立连接。
下列配置选项被用于两种模式:
ldapserver
要连接的 LDAP 服务器的名称或 IP 地址。可以指定多个服务器,用空格分隔。
ldapport
要连接的 LDAP 服务器的端口号。如果没有指定端口,LDAP 库的默认端口设置将被使用。
ldaptls
设置为 1 以使 PostgreSQL 和 LDAP 服务器之间的连接使用 TLS 加密。请注意,这里仅加密到 LDAP 服务器的流量 — 到客户端的连接将不被加密,除非使用 SSL。
下列选项只被用于简单绑定模式:
ldapprefix
当做简单绑定认证时,前置到用户名形成要用于绑定的 DN 的字符串。
ldapsuffix
当做简单绑定认证时,前置到用户名形成要用于绑定的 DN 的字符串。
下列选项只被用于搜索与绑定模式:
ldapbasedn
当做搜索与绑定认证时,开始搜索用户的根 DN。
ldapbinddn
当做搜索与绑定认证时,用户要绑定到目录开始执行搜索的 DN。
ldapbindpasswd
当做搜索与绑定认证时,用户用于绑定到目录开始执行搜索的口令。
ldapsearchattribute
当做搜索与绑定认证时,在搜索中用来与用户名匹配的属性。如果没有指定属性,将会使用uid
属性。
ldapurl
一个 RFC 4516 LDAP URL。这是一种用更紧凑和标准的形式书写某些其他 LDAP 选项的可选方法。格式是
ldap://host[:port]/basedn[?[attribute][?[scope]]]
scope
必须是base
、one
、sub
之一,通常是后者。只有一个属性会被使用,并且某些标准 LDAP URL 的其他部件(如过滤器和扩展)不被支持。
对于非匿名绑定,ldapbinddn
和ldapbindpasswd
必须被指定为独立选项。
要使用加密的 LDAP 连接,在ldapurl
之外还必须使用ldaptls
选项。ldaps
URL 模式(直接 SSL 连接)不被支持。
LDAP URL 当前只支持 OpenLDAP,而不支持 Windows。
将简单绑定的选项中混合用于搜索与绑定的选项是一种错误。
这里是一个简单绑定 LDAP 配置的例子:
host ... ldap ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net"
当请求一个作为数据库用户someuser
到数据库服务器的连接时,PostgreSQL 将尝试使用cn=someuser, dc=example, dc=net
和客户端提供的口令来绑定到 LDAP 服务器。如果那个连接成功,将被授予数据库访问。
这里是一个搜索与绑定配置的例子:
host ... ldap ldapserver=ldap.example.net ldapbasedn="dc=example, dc=net" ldapsearchattribute=uid
当请求一个作为数据库用户someuser
到数据库服务器的连接时,PostgreSQL 将尝试匿名绑定(因为没有指定ldapbinddn
)到 LDAP 服务器,在指定的基础 DN 下执行一次对于(uid=someuser)
的搜索。如果找到一个项,则它将尝试使用找到的信息和客户端提供的口令进行绑定。如果第二个连接成功,将被授予数据库访问。
这里是被写成一个 URL 的相同搜索与绑定配置:
host ... ldap ldapurl="ldap://ldap.example.net/dc=example,dc=net?uid?sub"
一些支持根据 LDAP 认证的其他软件使用相同的 URL 格式,因此很容易共享该配置。
如例子中所示,由于 LDAP 通常使用逗号和空格来分割一个 DN 的不同部分,在配置 LDAP 选项时通常有必要使用双引号包围的参数值。
这种认证方法的操作类似于password
,不过它使用 RADIUS 作为密码验证方式。RADIUS 只被用于验证 用户名/密码对。因此,在 RADIUS 能被用于认证之前,用户必须已经存在于数据库中。
当使用 RADIUS 认证时,一个访问请求消息将被发送到配置好的 RADIUS 服务器。这一请求将是Authenticate Only
类型,并且包含参数user name
、password
(加密的)和NAS Identifier
。该请求将使用一个与服务器共享的密钥加密。RADIUS 服务器将对这个服务器响应Access Accept
或者Access Reject
。不支持RADIUS accounting。
可以指定多个RADIUS服务器,在这种情况下,它们将按顺序尝试。 如果从服务器收到否定响应,则认证将失败。如果未收到响应, 则会尝试列表中的下一台服务器。要指定多个服务器,请将名称放在引号内, 并用逗号分隔服务器名称。如果指定了多个服务器, 则所有其他RADIUS选项也可以以逗号分隔的列表提供, 以将各个值应用于每个服务器。也可以指定为单个值,在这种情况下, 此值将应用于所有服务器。
下列被支持的配置选项用于 RADIUS:
radiusservers
连接到 RADIUS 服务器的名称或IP地址。此参数是必需的。
radiussecrets
和 RADIUS 服务器秘密交谈时会用到共享密钥。这在 PostgreSQL 和 RADIUS 服务器之间必须有完全相同的值。我们推荐用一个至少 16 个字符的字符串。这个参数是必需的。
如果PostgreSQL编译为支持OpenSSL,所用的加密向量将只是强密码。在其他情况下,到 RADIUS 服务器的传输应该被视为应该被视为被混淆的、不安全的。如有必要,应采用外部安全措施。
radiusports
用于连接到 RADIUS 服务器的端口号。如果没有指定端口,则使用默认端口1812
。
radiusidentifiers
在 RADIUS 请求中字符串被用作NAS Identifier
。 这个参数可以被用作第二个参数标识例如该用户试图以哪个数据库用户进行认证,它可以被用于 RADIUS 服务器上的策略匹配。如果没有指定标识符,默认使用postgresql
。
这种认证方法使用 SSL 客户端证书执行认证。因此,它只适用于 SSL 连接。当使用这种认证方法时,服务器将要求客户端提供一个有效的、可信的证书。不会有密码提示将被发送到客户端。证书的cn
(通用名)属性将与被请求的数据库用户名进行比较,并且如果匹配将允许登录。用户名映射可以被用来允许cn
与数据库用户名不同。
下列被支持的配置选项用于 SSL 证书认证:
map
允许在系统和数据库用户名之间的映射。详见第 20.2 节。
在一条指定证书认证的pg_hba.conf
记录中,认证选项clientcert
被假定为1
,并且它不能被关掉,因为这种方法中一个客户端证书是必需的。cert
方法对基本clientcert
证书验证测试所增加的东西是检查cn
属性是否匹配数据库用户名。
这种认证方法操作起来类似password
, 只不过它使用 PAM (插入式验证模块)作为认证机制。默认的 PAM 服务名是postgresql
。PAM 只被用于验证用户名/口令对并且可以有选择地验证已连接的远程主机名或 IP 地址。因此,在使用 PAM 进行认证之前,用户必须已经存在于数据库中。有关 PAM 的更多信息,请阅读 Linux-PAM 页面.
下列被支持的配置选项用于 PAM:
pamservice
PAM服务名称。
pam_use_hostname
判断是否通过PAM_RHOST
项把远程 IP 地址或者主机名提供给 PAM 模块。默认情况下会使用 IP 地址。把这个选项设置为 1 可以使用解析过的主机名。主机名解析可能导致登录延迟(大部分的 PAM 配置不使用这些信息,因此只有使用为利用这种信息而特别创建的 PAM 配置时才需要考虑这个设置)。
如果 PAM 被设置为读取/etc/shadow
,认证将会失败,因为 PostgreSQL 服务器是由一个非 root 用户启动 。然而,当 PAM 被配置为使用 LDAP 或其他认证验证方法时这就不是一个问题。
这种认证方法操作起来类似于password
,不过它使用 BSD 认证来验证口令。BSD 认证只被用来验证用户名/口令对。因此,在 BSD 认证可以被用于认证之前,用户的角色必须已经存在于数据库中。BSD 认证框架当前只在 OpenBSD 上可用。
PostgreSQL中的 BSD 认证使用auth-postgresql
登录类型,如果login.conf
中定义了postgresql
登录分类,就会用它来认证。默认情况下这种登录分类不存在,PostgreSQL将使用默认的登录分类。
要使用 BSD 认证,PostgreSQL 用户账号(也就是运行服务器的操作系统用户)必须首先被加入到auth
组中。在 OpenBSD 系统上默认存在auth
组。
本文转自PostgreSQL中文社区,原文链接:20.3. 认证方法