PostgreSQL安全性:快速查看身份验证最佳实践

72次阅读

共计 5696 个字符,预计需要花费 15 分钟才能阅读完成。

来源 | 愿码 (ChainDesk.CN) 内容编辑
愿码 Slogan | 连接每个程序员的故事
网站 | http://chaindesk.cn

愿码愿景 | 打造全学科 IT 系统免费课程,助力小白用户、初级工程师 0 成本免费系统学习、低成本进阶,帮助 BAT 一线资深工程师成长并利用自身优势创造睡后收入。
官方公众号 | 愿码 | 愿码服务号 | 区块链部落
免费加入愿码全思维工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码

本文阅读时长:11min
PostgreSQL 中的身份验证

身份验证回答了问题:谁是用户?PostgreSQL 支持一些 身份验证方法,包括以下内容:
· Trust 认证:任何可以连接到服务器的人都有权使用访问 pg_hba.conf 配置文件中指定的数据库 / 数据库。通常用于允许在单个用户计算机上使用 Unix 域套接字进行连接以访问数据库。此方法也可以与 TCP / IP 一起使用,但很少允许从本地主机以外的任何 IP 地址进行连接。
· Ident 认证:这通过从 ident 服务器获取客户端的操作系统用户名然后使用它来访问数据库服务器来工作。这个方法建议用于客户端计算机受系统管理员严格控制的封闭网络。
· Peer 认证:这类似于身份,但客户端操作系统用户名是从内核获得的。
· GSSAPI 认证:GSSAPI 是 RFC2743 中定义的行业标准。它提供自动身份验证(单点登录)。
· LDAP 认证:LDAP 服务器仅用于验证用户名 / 密码对。
· 密码认证:有以下三种方法
o SCRAM-SHA-256:PostgreSQL 10 中引入的最强的身份验证方法。此方法可防止对不受信任的连接进行密码嗅探。默认密码验证方法是 MD5 使用此功能,配置参数 password_encryption 应更改为 scram-sha-256
o MD5:MD5 具有已知的限制,例如:预先计算的查找表以破解密码哈希。此外,MD5 只有 40 亿个独特的哈希值。最后,MD5 计算速度非常快,因此暴力密码猜测不需要大量的 CPU 资源。对于新应用程序,建议仅使用 scram-sha-256。此外,PostgreSQL 提供了从 scram-sha-256 迁移的方法。
o Password:建议不要使用此密码,因为密码以明文格式发送到服务器。
要了解身份验证,您需要具有以下信息:
· 身份验证通过 pg_hba.conf 文件控制,其中 hba 代表基于主机的身份验证。
· 最好了解 PostgreSQL 发行版附带的默认初始身份验证设置
· pg_hba.conf 文件通常位于数据目录中,但也可以在 postgresql.conf 配置文件中指定。
更改身份验证时,您需要发送一个 SIGHUP 信号,这是通过基于 PostgreSQL 平台的几种方法完成的。注意,发送信号的用户应该是超级用户、Postgres 或 Linux 发行版上的根系统用户;同样,这取决于平台。以下是重新加载 PostgreSQL 配置的几种方法的示例:
psql -U postgres -c “SELECT pg_reload_conf();”
sudo service postgresql reload
sudo /etc/init.d/postgresql reload
sudo Kill -HUP
sudo systemctl reload postgresql-11.service
· 该订单的 pg_hba.conf 记录或条目是非常重要的。将会话连接 pg_hba.conf 逐个与记录进行比较,直到它被拒绝或到达配置文件的末尾。
· 最后,检查 PostgreSQL 日志文件以确定配置重新加载后是否存在错误是非常重要的。
PostgreSQL pg_hba.conf

与 postgresql.conf 一样,pg_hba.conf 文件由一组记录组成,可以使用哈希符号注释行,并且忽略空格。pg_hba.conf 文件记录的结构如下:
host_type database user [IP-address| address] [IP-mask] auth-method [auth-options]
host_type 查询的部分可以是以下内容:
· Local:在 Linux 系统中使用,允许用户使用 Unix 域套接字连接访问 PostgreSQL。
· Host:这是为了允许来自其他主机的连接,基于地址或 IP 地址,使用带有和不带 SSL 加密的 TCP / IP。
· Hostssl:这与主机类似,但应使用 SSL 加密连接。
· Hostnossl:这也与主机类似,但不应加密连接。
查询的数据库部分是用户想要连接的数据库的名称。为了提高灵活性,您还可以使用以逗号分隔的列表来指定多个数据库,或者可以 all 用来指示用户可以访问数据库集群中的所有数据库。此外,可以使用相同的用户和相同的角色值来指示数据库名称与用户名相同,或者用户是与数据库同名的角色的成员。
查询的用户部分指定数据库用户的名称;同样,all 值与所有用户匹配。IP 地址,地址和 IP 子网掩码用于标识用户所在的主机尝试连接。可以使用无类别域间路由(CIDR)或点十进制表示法指定 IP 地址。最后,密码验证方法可以信任,MD5,拒绝等。
以下是配置 PostgreSQL 身份验证的一些典型示例:
· 示例 1:PostgreSQL 集群上的任何用户都可以使用 Unix 域套接字访问任何数据库,如以下数据库表所示:
#TYPE DATABASE USER ADDRESS METHOD
Local all all trust
· 示例 2:PostgreSQL 集群上的任何用户都可以使用本地环回 IP 地址访问任何数据库,如以下数据库表所示:
#TYPE DATABASE USER ADDRESS METHOD
Host all all 127.0.0.1/32 trust
host all all ::1/128 trust
· 示例 3:192.168.0.53 拒绝来自 IP 地址的所有连接,来自 192.168.0.1/24 范围的连接被接受,如下数据库表所示:
#TYPE DATABASE USER ADDRESS METHOD
Host all all 192.168.0.53/32 reject
Host all all 192.168.0.1/24 trust
PostgreSQL 提供了一种非常方便的方法来查看 pg_hba.conf 文件中定义的规则,方法是提供一个名为 pg_hba_file_rules 的视图,如下所示:
postgres=# SELECT row_to_json(pg_hba_file_rules, true) FROM pg_hba_file_rules limit 1;
row_to_json
————————-
{“line_number”:84, +
“type”:”local”, +
“database”:[“all”], +
“user_name”:[“all”], +
“address”:null, +
“netmask”:null, +
“auth_method”:”trust”,+
“options”:null, +
“error”:null}
(1 row)
侦听地址

该 listen_addresses 选项定义于 postgresql.conf。PostgreSQL listen_addresses 连接设置用于标识服务器应从客户端应用程序侦听的 IP 地址列表。这些 listen_addresses 是以逗号分隔的主机名或 IP 地址列表。更改这个值需要重启服务器。此外,还应注意以下几点:
· 默认值为 localhost,它限制从网络到 PostgreSQL 集群的直接连接。
· 给出一个空列表意味着服务器应该只接受 Unix 套接字连接
· 该值 * 表示全部
对于新加入 PostgreSQL 的开发人员来说,忘记更改侦听地址是一个常见的错误。如果开发人员忘记更改,并尝试使用网络中的 TCP/IP 连接到 PostgreSQL,则会出现以下错误:
Connection refused Is the server running on host and accepting TCP/IP connections on port 5432?
认证最佳实践

身份验证最佳实践取决于整个基础架构设置,应用程序的性质,用户的特征,数据敏感性等。例如,以下设置对于初创公司很常见:数据库应用程序(包括数据库服务器)托管在同一台计算机上,并且仅由公司内部用户从一个物理位置使用。
通常,数据库服务器使用防火墙与世界隔离;在这种情况下,您可以使用 SCRAM-SHA-256 身份验证方法并限制 IP 地址,以便数据库服务器接受特定范围或集合内的连接。请注意,重要的是不要使用超级用户或数据库所有者帐户连接到数据库,因为如果此帐户被黑客入侵,则整个数据库集群将被暴露。
如果是应用服务器 – 业务逻辑 – 和数据库服务器不在同一台机器上,您可以使用强大的身份验证方法,例如 LDAP 和 Kerberos。但是,对于数据库服务器和应用程序位于同一台计算机上的小型应用程序,SCRAM-SHA-256 身份验证方法以及将侦听地址限制为 localhost 可能就足够了。
要对应用程序进行身份验证,建议仅使用一个用户,并尝试使用连接池软件减少允许的最大连接数,以便更好地调整 PostgreSQL 资源。在应用业务逻辑时可能需要另一级别的安全性来区分不同的登录用户。对于真实用户,更需要 LDAP 或 Kerberos 身份验证。
此外,如果从外部世界访问数据库服务器,则使用 SSL 证书加密会话以避免数据包嗅探很有用。
您还应该记住保护信任所有 localhost 连接的数据库服务器,因为访问 localhost 的任何人都可以访问数据库服务器。
角色系统和代理身份验证

通常,在设计应用程序时,登录角色用于配置数据库连接和连接工具。需要实现另一级安全性以确保使用该应用程序的用户被授权执行某项任务。该逻辑通常在应用程序业务逻辑中实现。
在使用事务块中的 SET SESSION AUTHORIZATION 语句或 SET ROLE 命令建立或重用连接后,通过将身份验证委派给另一个角色,数据库的角色系统也可用于部分实现此逻辑,如下所示:
postgres=# SELECT session_user, current_user;
session_user | current_user
————–+————–
postgres | postgres
(1 row)

postgres=# SET SESSION AUTHORIZATION test_user;
SET
postgres=> SELECT session_user, current_user;
session_user | current_user
————–+————–
test_user | test_user
(1 row)
设置角色需要角色成员资格,而设置会话授权需要超级用户权限。允许应用程序作为超级用户进行连接是危险的,因为可以分别使用 reset role 和 reset session 命令重置 set session authorization 和 set role 命令,从而允许应用程序获得超级用户权限。
为了了解如何使用 PostgreSQL 角色系统来实现身份验证和授权,我们将使用角色系统和汽车门户应用程序。在汽车门户应用程序中,可以将多组用户分类为 web-app-user、public-user、registered-user、seller-user 和 admin-user。web 应用程序用户用于配置业务逻辑连接工具;公共用户、注册用户和卖家用户用于区分用户。公共用户组只能访问公共信息,如广告,但不能作为注册用户添加评级,也不能创建广告,因为卖家用户。管理员用户是管理应用程序所有内容的超级角色,例如过滤垃圾邮件和删除不遵守网站策略的用户。当汽车门户网站应用程序连接到数据库时,将使用 Web 用户。之后,car_portal 将根据用户类调用 set role 命令。这种身份验证方法称为代理身份验证。
以下示例演示了如何使用角色系统来实现代理身份验证。第一步是创建角色并分配角色成员身份和权限,如下所示:
CREATE ROLE web_app_user LOGIN NOINHERIT;
CREATE ROLE public_user NOLOGIN;
GRANT SELECT ON car_portal_app.advertisement_picture, car_portal_app.advertisement_rating , car_portal_app.advertisement TO public_user;
GRANT public_user TO web_app_user;
GRANT USAGE ON SCHEMA car_portal_app TO web_app_user, public_user;
该 NOINHERIT 选项 web_app_user 不允许用户继承角色成员资格的权限;但是,web_app_user 可以将角色更改为公共用户,如以下示例所示:
$ psql car_portal -U web_app_user

car_portal=> SELECT * FROM car_portal_app.advertisement;
ERROR: permission denied for relation advertisement
car_portal=> SET ROLE public_user;
SET
car_portal=> SELECT * FROM car_portal_app.advertisement;
advertisement_id | advertisement_date | car_id | seller_account_id
——————+——————–+——–+——————-
(0 rows)

car_portal=> SELECT session_user, current_user;
session_user | current_user
————–+————–
web_app_user | public_user
(1 row)

正文完
 0