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

image
  • 来源 | 愿码(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)

你可能感兴趣的:(PostgreSQL安全性:快速查看身份验证最佳实践)