Avinash Vallarapu是Percona的PostgreSQL支持技术负责人。
又一个月, 又一次数据库安全灾难 。 随着不良行为者意识到数据库包含大量数据 , 数据库安全漏洞似乎正变得越来越普遍 。
这种情况如何发生? 通常,答案是执行不佳的数据库安全协议。 我们如何阻止它发生?
好消息是它是可以预防的。 只要您采取必要的预防措施,数据库就不必冒险。 通常答案是配置。 不要只使用开箱即用的设置。 不要使用iptables来保护访问。 (只要可以在最近的Exactis漏洞中确定,如果设置使用iptables或类似功能,则可以避免该漏洞。)
在本文中,我们将介绍可采取的步骤来保护PostgreSQL免受入侵和攻击。 首先,我们将研究在PostgreSQL中实现SSL连接和基于证书的身份验证。 然后,我们将研究如何在PostgreSQL中创建提供最低级别的数据库访问权限的用户和组。
PostgreSQL是一个久经考验的开源数据库,已在许多企业和启动数据库部署中使用。 PostgreSQL中肯定有很多数据需要保护。
在PostgreSQL中配置安全连接
PostgreSQL允许您通过SSL通过网络启用数据加密。 PostgreSQL使用SSL连接来加密客户端和服务器之间的通信。 为了使用SSL,必须在客户端和服务器上都安装了OpenSSL。
使用SSL加密连接的步骤
若要继续进行,您必须创建由证书颁发机构签名的服务器和客户端证书文件。
1.创建证书签名请求(CSR)和密钥文件。
$ openssl genrsa -out rootCA.key 1024
$ openssl req -x509 -new -key rootCA.key -days 365 -out rootCA.crt -subj '/C=XX/L=Default City/O=Default Company Ltd/CN=root'
2.创建由根证书颁发机构签名的服务器证书。
$ openssl genrsa -out server.key 1024
$ openssl req -new -key server.key -out server.csr -subj '/C=XX/L=Default City/O=Default Company Ltd/CN=pgservername'
$ openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 365
(请注意,上面第二行中的CN
应该是用于服务器验证的服务器名称。)
3.创建由根证书颁发机构签名的客户端证书。
$ openssl genrsa -out postgresql.key 1024
$ openssl req -new -key postgresql.key -out postgresql.csr -subj '/C=XX/L=Default City/O=Default Company Ltd/CN=postgres'
$ openssl x509 -req -in postgresql.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out postgresql.crt -days 365
4.将服务器证书文件(server.crt),服务器私钥(server.key)和根证书颁发机构(rootCA.crt)复制到PostgreSQL数据目录或PostgreSQL超级用户(postgres)可访问的安全位置。 复制后,请授予PostgreSQL用户只读权限。
$ cd $PGDATA
$ chmod 0400 server.crt server.key rootCA.crt
5.在PostgreSQL中设置适当的参数以启用SSL模式。
$ psql
ALTER SYSTEM SET ssl TO 'ON';
ALTER SYSTEM SET ssl_ca_file TO 'root.crt';
ALTER SYSTEM SET ssl_cert_file TO 'server.crt';
ALTER SYSTEM SET ssl_key_file TO 'server.key';
6. OpenSSL支持多种密码 。 您将要选择适合您的组织标准的密码。 选择了要使用的密码后,在PostgreSQL中设置以下参数。
psql
ALTER SYSTEM SET ssl_ciphers TO 'your_desired_cipher'; (=> Change requires Server Reload)
默认密码为: HIGH:MEDIUM:+3DES:!aNULL
7.您可以重新加载或重新启动PostgreSQL服务器以使这些参数生效。
$ psql -c "select pg_reload_conf()"
要么
$ pg_ctl -D $PGDATA restart -mf
8.要使用SSL启用加密,必须在pg_hba.conf文件中将host修改为hostssl。 例如,要为本地连接启用SSL,请使用hostssl替换host进行本地连接。
$ vim $PGDATA/pg_hba.conf
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# IPv4 local connections:
# host all all 127.0.0.1/32 trust
hostssl all all 127.0.0.1/32 trust
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
9.您可以添加类似的条目以对来自远程应用程序或客户端的连接进行加密。
$ vim $PGDATA/pg_hba.conf
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# IPv4 local connections:
# host all all 127.0.0.1/32 trust
hostssl all all 127.0.0.1/32 trust
hostssl all all app_server_1/32 md5
hostssl all all app_server_2/32 md5
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
10.对pg_hba.conf文件进行更改后,必须执行SIGHUP或重新加载。
$ psql -c "select pg_reload_conf()"
11.测试本地连接的SSL。 这是为本地连接启用SSL之前和之后的外观。
之前
=======
$ psql -h localhost
psql (10.4)
Type "help" for help.
postgres=#
后
=======
$ psql -h localhost
psql (10.4)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off)
Type "help" for help.
postgres=#
如果将hostssl用于远程应用程序连接,则与数据库服务器的通信将自动加密。
启用客户端证书身份验证的步骤
12.客户端或应用程序服务器可以将客户端证书用于用户身份。 这对于身份验证特别有用。 现在,您可以将在步骤3(上面)中生成的客户端证书复制到远程应用程序服务器上。 复制后,设置适当的权限。 例如,用于此测试的我的应用程序服务器的IP是192.168.0.13。
$ scp postgresql.crt postgresql.key rootCA.crt postgres@192.168.0.13:/var/lib/pgsql
复制到应用程序服务器后,向应用程序服务器中的相应OS用户授予只读特权。
$ chmod 0400 postgresql.crt postgresql.key rootCA.crt
13.为了使用客户端证书认证,请将以下条目添加到远程PostgreSQL服务器的pg_hba.conf中。
$ vi $PGDATA/pg_hba.conf
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
hostssl all all 192.168.0.13/32 cert clientcert=1
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
此处,192.168.0.13是应用程序服务器的IP地址。 您可能希望以这种方式有多个条目。
注意步骤9和步骤13之间的区别。步骤9中的pg_hba.conf条目将启用加密通信,并自动加密连接。 步骤13中的pg_hba.conf条目更进一步。 它还将强制客户端认证身份验证,以确保在受信方之间进行通信。
给出SIGHUP或重新加载以使对pg_hba.conf的更改生效。
$ pg_ctl -D $PGDATA reload
14.使用psql客户端验证远程连接。
$ psql "port=5432 host=192.168.0.12 user=postgres sslcert=/var/lib/pgsql/postgresql.crt sslkey=/var/lib/pgsql/postgresql.key sslrootcert=/var/lib/pgsql/rootCA.crt sslmode=require"
psql (10.4)
SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-DES-CBC3-SHA, bits: 168, compression: off)
Type "help" for help.
postgres=#
您应该看到通过SSL进行的连接。
在PostgreSQL中创建安全的用户和组角色
PostgreSQL允许您通过SSL通过网络启用数据加密。 但是,了解安全强化和用户管理在PostgreSQL中的工作方式也很重要。 PostgreSQL中的用户必须具有适当的特权,这些特权不会给予过多的访问权限。 以下步骤应有助于您了解PostgreSQL如何实现用户管理。 他们还提出了一些最佳做法。
什么是PostgreSQL用户?
PostgreSQL用户是具有CONNECT特权的角色 。 CREATE USER
和CREATE ROLE
可以很好地创建PostgreSQL用户。 但是,用户必须具有LOGIN角色。 当您使用以下三种方法之一时,登录角色将分配给用户:
CREATE USER percuser WITH ENCRYPTED PASSWORD 'secret';
要么
CREATE ROLE percuser WITH ENCRYPTED PASSWORD 'secret';
要么
CREATE ROLE percuser;
ALTER ROLE percuser WITH LOGIN ENCRYPTED PASSWORD 'secret';
当您将CREATE USER
与以上任何一种配合使用时,PostgreSQL会使用以下内容自动在内部修改语法:
CREATE ROLE percuser
WITH NOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB LOGIN NOREPLICATION NOBYPASSRLS
ENCRYPTED PASSWORD 'secret';
在PostgreSQL自动修改的上述语法中,我们看到它没有授予管理PostgreSQL所需的角色。
创建用户或角色后,您可以使用以下查询查看用户是否可以登录(具有CONNECT特权):
postgres=# select rolcanlogin from pg_roles where rolname = 'percuser';
rolcanlogin
-------------
t
(1 row)
这将返回一个布尔值,告知用户是否可以登录。 例如,当您使用以下语法创建ROLE时,您会看到该角色没有CONNECT特权。
postgres=# CREATE ROLE percrole;
CREATE ROLE
postgres=# select rolcanlogin from pg_roles where rolname = 'percrole';
rolcanlogin
-------------
f
(1 row)
请注意:始终避免使用前缀pg_%创建任何用户或角色。
PostgreSQL中CREATE USER和CREATE ROLE之间的区别
使用CREATE USER
,该用户将自动获得LOGIN角色:
postgres=# CREATE USER percuser WITH ENCRYPTED PASSWORD 'secret';
CREATE ROLE
postgres=# select rolcanlogin from pg_roles where rolname = 'percuser';
rolcanlogin
-------------
t
(1 row)
但是,在创建角色时,必须显式添加LOGIN角色以允许用户登录:
postgres=# CREATE ROLE percuser WITH ENCRYPTED PASSWORD 'secret';
CREATE ROLE
postgres=# select rolcanlogin from pg_roles where rolname = 'percuser';
rolcanlogin
-------------
f
(1 row)
postgres=# ALTER ROLE percuser WITH LOGIN;
ALTER ROLE
postgres=# select rolcanlogin from pg_roles where rolname = 'percuser';
rolcanlogin
-------------
t
(1 row)
PostgreSQL中的组或组角色是什么?
在PostgreSQL中,角色可以继承其他角色。 这意味着一个角色可以使用另一角色的特权进行访问。 可以使用GRANT或INHERIT关键字来实现。
始终建议使用GROUP ROLES为用户提供访问权限。
例如,考虑具有以下条件的组织:
- 1个数据库( percona )
- 2种模式( 斯科特和老虎 )
假设我们然后需要创建10个个人用户和10个应用程序用户,并遵守以下要求:
- 应用程序用户中的五个必须对模式scott的表具有只读访问权限,并且对模式tiger的表具有读写访问权限。
- 其他五个应用程序用户必须对模式scott的表具有读写访问权限,并且对模式tiger的表具有只读访问权限。
- 所有10个单独的用户帐户都只能对scott和tiger模式表进行只读访问。
在这种情况下,您可以创建四个组角色,如下所示:
scott_readonly :
CREATE ROLE scott_readonly;
GRANT USAGE, SELECT ON ALL TABLES IN SCHEMA scott TO scott_readonly;
scott_readwrite :
CREATE ROLE scott_readwrite;
GRANT USAGE, SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA scott TO scott_readwrite;
tiger_readonly :
CREATE ROLE tiger_readonly;
GRANT USAGE, SELECT ON ALL TABLES IN SCHEMA tiger TO tiger_readonly;
tiger_readwrite :
CREATE ROLE tiger_readwrite;
GRANT USAGE, SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA tiger TO tiger_readwrite;
现在,你可以GRANT
这些群组角色基于上述三个要求的用户。
GRANT scott_readonly,tiger_readonly TO user1;
GRANT scott_readonly,tiger_readwrite TO appuser1;
GRANT scott_readwrite,tiger_readonly TO appuser2;
通过将组角色分配给这些用户,您可以隔离允许哪个用户获得哪些特权。
参考: https : //www.postgresql.org/docs/10/static/sql-createrole.html
用户和角色是否对整个实例都是全局的?
是的,PostgreSQL中的用户和角色对于整个实例都是全局的。 一个用户可以用来访问任何数据库。 同样,可以向PostgreSQL中的组角色授予多个数据库中多个模式/对象的特权。
下面的示例显示组角色(授予) scott_readonly对两个不同数据库的两个不同表具有SELECT特权:
From: https://www.infoworld.com/article/3306441/how-to-secure-your-postgresql-database.html