PostgreSQL7.0手册-管理员手册-28. 安全性
内容
用户认证
用户名和组
访问控制
函数和规则
安全 TCP/IP 联接
数据库安全性分成几个级别:
数据库文件保护。所有在数据库里存储的文件都受到保护,除了Postgres 超级用户帐户外其他用户是不能读取的。
缺省的时候,客户端只能通过一个本地的 Unix 套接字联接到数据库服务器上来,而不是通过 TCP/IP 套接字。后端必须带 -i 选项启动才能允许非本地的客户端联接上来。
可以通过在 PG_DATA 里的 pg_hba.conf 文件来限制可联接的客户端 IP 地址和/或用户名。
客户端联接可以通过其他外部软件包来认证。
Postgres 里的每个用户都赋予了一个用户名和一个(可选的)口令。缺省是,用户对不是他们创建的数据库没有写权限。
用户可以赋予组,而且表的访问权限可以以组权限为基础设置。
用户认证
认证是后端服务器和 postmaster 认定正在请求访问数据的用户就是他/她自称的那个人的过程。所有激活Postgres 的用户都对照 pg_user 表的内容进行检查以确保他们有这么做的权限(激活数据库)。不过,对用户的实际身份的的核对是通过好几种方式进行的:
从用户 shell 来的用户
从用户 shell 启动的后端数据库服务器在进行一个 setuid 调用把用户标识转为用户 postgres 之前要检查用户的(有效的)用户标识。有效的用户标识被当作访问控制检查的基础。不进行其他的认证。
从网络来的用户
如果 Postgres 系统是为分布(处理)制作的,任何人都可以访问postmaster 进程的网际网的 TCP 端口。DBA 配置在 PGDATA 目录里的 pg_hba.conf 文件,根据访问从哪个主机来和要访问哪个数据库声明需要采用的认证方式。参阅 pg_hba.conf(5) 获取一份可以使用的认证系统的描述。当然,在 Unix 里,以主机为基础的认证也不是无懈可击的。有能力的入侵者也可能伪装源主机(地址)。那些安全性问题超越了Postgres 的范畴。
以主机为基础的访问控制
以主机为基础的访问控制 是 PostgreSQL 决定哪些客户端可以访问数据库以及那些客户端上的用户如何认证他们自己的基本控制的名称。
每个数据库系统都包含一个文件叫 pg_hba.conf,在其 PGDATA 目录里,该文件控制谁可以联接到各自的数据库。
每个正在访问数据库的客户端必须被 pg_hba.conf 里的其中一条记录涵盖。否则所有从那个客户端发送上来的联接请求都将被拒绝,错误信息为 "User authentication failed" (用户认证失败)。
文件 pg_hba.conf 的常用格式是一套记录,每行一条。空白行或者杂乱符号("#")开头的行被忽略。一条记录是由若干用空格和/或 tab 分隔的字段组成。
从客户端来的联接可以使用 Unix 域套接字或者网际网域套接字(例如:TCP/IP)建立。用 Unix 域套接字进行的联接是用下面格式的记录进行控制的:
local database authentication method
这里
database 声明记录所应用的数据库。值 all 表明该记录应用于所有数据库。
authentication method 声明一个用户在用 Unix 域套接字与该数据库联接时用于认证他们自身的方法。不同的方法在下面描述。
用网际网(IP)域套接字进行的联接是用下面格式的记录进行控制的:
host database TCP/IP address TCP/IP mask authentication method
TCP/IP address 逻辑上与声明的 TCP/IP mask 和正在联接的客户端的 TCP/IP 地址分别相加。如果两个结果相等则该记录用于这次联接。如果一个联接匹配多于一条记录,那么使用文件里第一条匹配的记录。 TCP/IP address 和 TCP/IP mask 都是用点分十进制符号表示的。
如果一个联接不能和任何记录相匹配,则应用拒绝认证方法(见下文)。
认证方法
下面的认证方法可用于 Unix 和 TCP/IP 域套接字:
trust
无条件允许联接。
reject
无条件拒绝联接。
crypt
客户端被要求向用户请求一个口令。该口令被加密后(使用 crypt(3))发送,然后与放在 pg_shadow 表里的口令进行比较。如果口令匹配,则允许联接。
password
客户端被要求向用户请求一个口令。该口令以明文发送,然后与放在 pg_shadow 表里的口令进行比较。如果口令匹配,则允许联接。可以在 password 关键字后面声明一个可选的文件名,用于提供对应的口令而不是使用 pg_shadow 表里面的。参阅 pg_passwd。
下面的认证方式只能用于 TCP/IP 域套接字:
krb4
Kerberos V4 用于认证用户。
krb5
Kerberos V5 用于认证用户。
ident
在客户端的 ident 服务器用于认证该用户(RFC 1413)。可以在 ident 关键字后面声明一个可选的映射名,这样允许 ident 用户名映射成Postgres 用户名。映射放在文件 $PGDATA/pg_ident.conf 里。
例子
# Trust any connection via Unix domain sockets.
local trust
# Trust any connection via TCP/IP from this machine.
host all 127.0.0.1 255.255.255.255 trust
# We don't like this machine.
host all 192.168.0.10 255.255.255.0 reject
# This machine can't encrypt so we ask for passwords in clear.
host all 192.168.0.3 255.255.255.0 password
# The rest of this group of machines should provide encrypted passwords.
host all 192.168.0.0 255.255.255.0 crypt
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
用户名和组
要定义一个新用户,运行工具程序 createuser。
要把一个用户或者一套用户指派到一个新组,我们必须先定义该组,然后分派用户到该组中去。在Postgres 里,这些步骤目前还不被一条 create group 命令支持(译注:已经支持了)。代替的做法是,向 pg_group 系统表里插入一些合适的值,然后用 grant 命令给组赋予权限。
创建用户
创建组
目前,我们还没有简便的方法设置用户组。你必须显式地插入/更新 pg_group 表。例如:
jolly=> insert into pg_group (groname, grosysid, grolist)
jolly=> values ('posthackers', '1234', '{5443, 8261}');
INSERT 548224
jolly=> grant insert on foo to group posthackers;
CHANGE
jolly=>
pg_group 里的域是:
groname
组名称。这个名称应该是纯数字和字母组成。不要包含下划线和其他标点。
grosysid
组标识。这是一个 int4。这个字段应该在各个组之间唯一。
grolist
属于这个组的 pg_user id (标识)的列表。这个字段是一个 int4[]。
把用户分派到组
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
访问控制
Postgres 提供允许用户限制其他用户对他提供的数据的访问的机制。
数据库超级用户
数据库超级用户(也就是说,拥有设置了 pg_user.usesuper 字段的用户)超越下面描述的所有访问控制,只有两点例外:如果用户没有设置了的 pg_user.usecatupd 字段,则不允许手工更新系统表,第二点是决不允许删除(或者更改表结构)系统表。
访问权限
限制用户对表的读,写和设置规则的的访问权限在 grant/revoke(l) 里描述。
表删除和表结构修改
象 alter,drop table,和 drop index 这样的删除或者修改现有表的命令只能由表的所有者执行。还有上面提到的,决不允许对系统表进行这些操作。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
函数和规则
函数和规则允许用户在其他用户可能不知道的情况下向后端服务器里插入代码。因此,两种机制都允许用户使用特洛伊木马对付其他用户。唯一有效的保护措施是牢牢控制谁可以定义函数(即是向关系中写入 SQL 域)和规则。我们还建议在 pg_class,pg_user 和 pg_group 上设置跟踪和警告器。
函数
用 SQL 以外的语言写的在后端服务器进程里运行的函数拥有用户 postgres 的权限(后端服务器带着设置为 postgres 的真实有效的用户标识运行。)用户有可能从一个被信任的函数里面修改服务器的内部数据结构。因此,除了别的问题外,这样的函数可以巧取任何系统访问控制。这是一个用户定义的 C 函数的固有毛病。
规则
就象 SQL 函数一样,规则总是以激活后端服务器的用户的标识和权限运行。
注意事项
我们没有计划准备显式地支持 Postgres 内部数据的加密(当然我们无法阻止用户在用户定义函数里对数据进行加密)。我们也没有计划准备显式地支持加密的网络联接,那样将导致前/后端协议的完全重写。
用户名,组名和相关系统标识(比如,pg_user.usesysid 的内容)都是假设在整个数据库里唯一的。如果不是这样,会造成不可预料的结果。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
安全 TCP/IP 联接
作者:来自一封 Gene Selkov, Jr. 的 e-mail。于 1999-09-08 为回答 Eric Marsden 的一个问题而作。
我们可以使用 ssh 来对 Postgres 服务器和客户端之间的网络联接进行加密。经过适当处理后,这样做可以获得一个足够安全的网络联接。
ssh 的文档提供了前期了解所需的大多数信息。请参考 http://www.heimhardt.de/htdocs/ssh.html 获取更多信息。
我们可以只用两个步骤做一次分步解释。
通过 shh 运行一个安全的通道
我们可以只用两个步骤做一次分步解释。
建立一个与后端机器的通道,象这样:
ssh -L 3333:wit.mcs.anl.gov:5432 postgres@wit.mcs.anl.gov
-L 参数的第一个数字 3333,是通道你这端的端口号。第二个数字,5432,是通道的远端 -- 你的后端使用的端口号。在两个端口号之间的名称或者地址属于服务器机器,ssh 的最后一个参数也是属于服务器机器,它还包括可选的用户名。如果没有用户名,ssh 将使用你登录到客户端机器的这个用户名。你可以使用任何服务器机器接受的用户名,而不一定是那些与 postgres 有关的。
既然你已经有了一个正在运行的 ssh 会话,那么你就可以把一个 postgres 客户端与你本地主机上的那个你在上一步里声明的端口号联接了。如果是psql,你将需要另一个 shell,因为你在第一步里使用的 shell 会话现在被 ssh 占着呢。
psql -h localhost -p 3333 -d mpw
注意你必须声明 -h 参数以便让你的客户端使用 TCP 套接字而不是 Unix 套接字。如果你选择 5432 作为通道你这一端的端口,你可以省略端口参数。
--------------------------------------------------------------------------------