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

  • 来源 | 愿码(ChainDesk.CN)内容编辑
  • 愿码Slogan | 链接每一个程序员的故事
  • 网站 | http://chaindesk.cn
  • 愿码愿景 | 打造全学科IT系统免费课程,助力小白用户、初级工程师0成本免费系统学习、低成本进阶,帮助BAT一线资深工程师成长并利用自身优点创造睡后收入。
  • 官方公众号 | 愿码 | 愿码服务号 | 区块链部落
  • 免费加入愿码全思惟工程师社群 | 任一公众号回复“愿码”两个字获取入群二维码

本文阅读时长:11min程序员

PostgreSQL中的身份验证


身份验证回答了问题:谁是用户?PostgreSQL支持一些 身份验证方法,包括如下内容:web

· Trust认证:任何能够链接到服务器的人都有权使用访问pg_hba.conf配置文件中指定的数据库/数据库。一般用于容许在单个用户计算机上使用Unix域套接字进行链接以访问数据库。此方法也能够与TCP / IP一块儿使用,但不多容许从本地主机之外的任何IP地址进行链接。 sql

· Ident认证:这经过从ident服务器获取客户端的操做系统用户名而后使用它来访问数据库服务器来工做。这个方法建议用于客户端计算机受系统管理员严格控制的封闭网络。数据库

· Peer认证:这相似于身份,但客户端操做系统用户名是从内核得到的。json

· GSSAPI认证:GSSAPI是RFC2743中定义的行业标准。它提供自动身份验证(单点登陆)。安全

· LDAP认证: LDAP服务器仅用于验证用户名/密码对。服务器

· 密码认证:有如下三种方法网络

o SCRAM-SHA-256:PostgreSQL 10中引入的最强的身份验证方法。此方法可防止对不受信任的链接进行密码嗅探。默认密码验证方法是MD5使用此功能,配置参数 password_encryption应更改成 scram-sha-256session

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)
相关文章
相关标签/搜索