如何保护PostgreSQL免受自动攻击

在本教程中,我们将展示一个重要的第一步,以减轻在配置PostgreSQL以允许远程连接时可能创建的特定风险。虽然这是重要的第一步,由于服务器可能以其他方式受到损害,我们还建议您采取额外的措施保护您的数据,在[其他安全注意事项](#additional-security-configuration)一节中概述。

介绍

它可以是诱人的想法,因为服务器刚刚被提出,看到很少的交通,或提供没有什么,似乎有价值的黑客,它会被忽视。然而,许多漏洞利用是自动的,并且专门设计用于寻找配置中的常见错误。这些程序扫描网络以发现服务器,而与内容的性质无关。 允许远程连接是常见的,更容易纠正的情况之一,可能导致PostgreSQL数据库的利用。这是因为某些配置使得像这样的程序很容易发现服务器。 在本教程中,我们将展示如何通过允许远程连接来减轻特定风险。虽然这是重要的第一步,但由于服务器可能以其他方式受到损害,我们还建议您采取其他措施来保护您的数据,如“ 其他安全注意事项”中所述。

背景

要了解我们正在缓解的具体风险,将服务器设想为商店。如果服务器正在监听任何端口,它有点像打开霓虹灯“打开”的标志。它使服务器本身在网络上可见,自动化脚本可以在网络上找到它。 我们可以认为每个端口都是进入商店的方式,像门或窗户。这些入口可能是打开,关闭,锁定或破坏,这取决于正在监听的软件的状态,但是在公共接口上监听意味着一个寻求进入的脚本可以开始尝试。例如,脚本可能被配置为尝试使用默认密码登录,但没有被更改的机会。它可能尝试已知的漏洞守护进程的漏洞,以防它未被修补。无论脚本尝试,如果它能够找到一个弱点并利用它,那么入侵者是在内部,可以下到严重的服务器妥协的业务。 当我们限制一个像postgresql这样的守护进程在本地监听时,就像外面的特定门不存在。 没有下一步要尝试,至少对于Postgres。 防火墙和VPN以类似的方式保护。 在本教程中,我们将重点介绍将PostgreSQL作为可公开访问的门户。 要保护守护程序本身或传输或存储的数据,请参阅其他安全注意事项

先决条件

在本教程中,我们将使用两个Ubuntu安装 ,一个用于数据库主机,一个用作将远程连接到主机的客户端。 每个应该有一个sudo用户和防火墙启用。 指南, 与Ubuntu 16.04的初始服务器设置可以帮助您。 一个Ubuntu 16.04 PostgreSQL数据库主机 : 如果您尚未安装PostgreSQL,可以使用以下命令:
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib
一个Ubuntu 16.04客户端机器 : 为了演示和测试允许远程连接,我们将使用PostgreSQL客户端, psql 。要安装它,请使用以下命令:
sudo apt-get update
sudo apt-get install postgresql-client
当这些先决条件到位后,您就可以随时跟进。

了解默认配置

当PostgreSQL从Ubuntu软件包安装时,默认情况下它被限制为监听localhost。可以通过覆盖postgresql.conf文件中的postgresql.conf来更改此默认值,但默认值会阻止服务器自动监听公共接口。 此外, pg_hba.conf文件仅允许来自Unix / Linux域套接字的连接和服务器的本地环回地址,因此它不会接受来自外部主机的连接:
更换
# Put your actual configuration here
# ----------------------------------
#
# If you want to allow non-local connections, you need to add more
# "host" records.  In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.

# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local   all             postgres                                peer

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5
这些默认值满足不在公共接口上监听的目的。如果我们把它们完好和保持防火墙,我们完成了!我们可以直接进入其他安全注意事项 ,了解如何保护传输中的数据。 如果您需要从远程主机进行连接,我们将介绍如何覆盖默认值,以及您在下一节中可以采取的保护服务器的即时步骤。

配置远程连接

对于生产设置,在开始处理敏感数据之前,理想情况下,我们将在传输中使用SSL加密PostgreSQL流量,并在外部防火墙之后或受虚拟专用网络(VPN)保护。在我们努力实现这一点时,我们可以采取一些不那么复杂的步骤,在我们的数据库服务器上启用防火墙,并限制对需要它的主机的访问。

第1步 - 添加用户和数据库

我们将首先添加一个用户和数据库,这将允许我们测试我们的工作。为此,我们将使用PostgreSQL客户端psql作为管理用户postgres进行连接。 通过将-i选项传递给sudo我们将运行postgres用户的登录shell,这将确保我们从.profile或其他特定于登录的资源加载选项。 -u物种postgres用户:
sudo -i -u postgres psql
接下来,我们将使用密码创建一个用户。请务必使用安全密码代替下面突出显示的示例:
CREATE USER sammy WITH PASSWORD 'password';
当用户成功创建时,我们应该收到以下输出:
CREATE ROLE
注意:由于PostgreSQL 8.1,ROLES和USERS是同义词。按照惯例,具有密码的角色仍称为USER,而角色不称为ROLE,因此有时我们会在输出中看到ROLE,我们可能期望看到USER。 接下来,我们将创建一个数据库,并授予我们对新用户的完全访问权限。最佳做法建议我们仅向用户授予他们所需的访问权限,并且仅授予他们应拥有的权限,因此,根据用例,可能适当限制用户的访问权限。您可以在指南中了解有关权限的更多信息如何在VPS上使用 PostgreSQL中的角色和管理授予权限
CREATE DATABASE sammydb OWNER sammy;
当数据库创建成功时,我们应该收到确认:
CREATE DATABASE
现在,我们已经创建了一个用户和数据库,我们将退出监视器
\q
按ENTER键后,我们将在命令提示符下,并准备继续。

第2步 - 配置UFW

初始服务器设置与Ubuntu 16.04先决条件,我们启用UFW和只允许的SSH连接。在我们开始配置之前,让我们验证UFW的状态:
sudo ufw status
注意:如果输出指示防火墙处于inactive我们可以使用以下命令激活它:
sudo ufw enable
一旦启用,重新运行状态命令, sudo ufw status将显示当前规则。如有必要,请确保允许SSH。
sudo ufw allow OpenSSH
除非我们对先决条件进行了更改,否则输出应显示仅允许OpenSSH:
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
现在我们已经检查了防火墙状态,我们将允许访问PostgreSQL端口并将其限制到我们想要允许的主机。 下面的命令将添加PostgreSQL默认端口的规则,即5432.如果您更改了该端口,请务必在以下命令中更新它。确保您已使用需要访问的服务器的IP地址。如果需要,请重新运行此命令以添加需要访问的每个客户端IP地址:
sudo ufw allow from client_ip_address to any port 5432
要仔细检查规则,我们可以再次运行ufw status
sudo ufw status
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
5432                       ALLOW       client_ip_address
OpenSSH (v6)               ALLOW       Anywhere (v6)
注意:如果您是UFW的新用户,您可以在UFW Essentials:常见防火墙规则和命令指南中了解更多信息。 有了这个防火墙规则,我们现在将配置PostgreSQL监听其公共IP地址。这需要两个设置的组合,pg_hba.conf中连接主机的一个条目和postgresql.conf中listen_addresses的postgresql.conf

第3步 - 配置允许的主机

我们将在pg_hba.conf中添加主机条目。如果您安装了不同版本的PostgreSQL,请务必在以下路径中替换它:
sudo nano /etc/postgresql/9.5/main/pg_hba.conf
我们将host行放在描述如何允许非本地连接的注释块下。我们还将包括一个具有数据库服务器的公共地址的行,以便我们可以快速测试我们的防火墙配置是否正确。请确保在下面的示例中替换机器的主机名或IP地址。
摘自pg_hba.conf
# If you want to allow non-local connections, you need to add more
# "host" records.  In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
host  sammydb  sammy   client_ip_address/32   md5
在保存更改之前,让我们关注此行中的每个值,以便您更改某些选项时:
  • host第一个参数host ,确定将使用TCP / IP连接。
  • 数据库 sammydb第二列指示主机可以连接到的数据库。可以通过用逗号分隔名称来添加多个数据库。
  • 用户 sammy表示允许进行连接的用户。与数据库列一样,可以指定多个用户,用逗号分隔。
  • address该地址指定客户端计算机地址,可能包含主机名,IP地址范围或其他特殊关键字 。在上面的示例中,我们只允许我们客户端的单个IP地址。
  • auth-method最后,auth方法, md5表示将提供用于身份验证的双MD5哈希密码 。您只需提供为用户连接创建的密码,则无需执行任何操作。
有关这些和其他设置的更完整的讨论,请参阅pg_hba.conf文件 PostgreSQL文档。 完成后,保存并退出文件。

第4步 - 配置监听地址

接下来,我们将在postgresql.conf文件中设置监听地址:
sudo nano /etc/postgresql/9.5/main/postgresql.conf
找到listen_addresses行及其下面,定义您的监听地址,确保替换数据库主机的主机名或IP地址。您可能需要仔细检查是否使用数据库服务器的公共IP,而不是连接的客户端:
postgresql.conf
#listen_addresses = 'localhost'         # what IP address(es) to listen on;
listen_addresses = 'localhost,server_ip_address'
完成后保存并退出文件。

第5步 - 重新启动PostgreSQL

我们的配置更改将不会生效,直到我们重新启动PostgreSQL守护进程,所以我们将在测试之前:
sudo systemctl restart postgresql
由于systemctl不提供反馈,我们将检查状态以确保守护程序成功重新启动:
sudo systemctl status postgresql
如果输出包含“活动:活动”并以类似以下内容结束,则PostgreSQL守护程序正在运行。
...
Jan 10 23:02:20 PostgreSQL systemd[1]: Started PostgreSQL RDBMS.
现在我们已经重新启动了守护进程,我们准备测试了。

第6步 - 测试

最后,让我们测试我们可以从客户端机器连接。为此,我们将使用psql-U指定用户, -h指定客户端的IP地址,使用-d指定数据库,因为我们收紧了我们的安全性,以便sammy只能连接到单个数据库。
psql -U sammy -h postgres_host_ip -d sammydb
如果一切配置正确,您应该会收到以下提示:
Password for user sammy:
输入您在PostgreSQL监视器中添加用户sammy时早先设置的密码。 如果您到达以下提示,表示您已成功连接:
[secondary_label]
sammydb=>
这确认我们可以通过防火墙并连接到数据库。我们现在就退出:
\q
由于我们已经确认我们的配置,我们将完成清理。

第7步 - 删除测试数据库和用户

回到主机一旦我们完成测试连接,我们可以使用以下命令删除数据库和用户以及。
sudo -i -u postgres psql
删除数据库:
DROP DATABASE sammydb;
该操作通过以下输出确认:
DROP DATABASE
要删除用户:
DROP USER sammy;
成功通过以下方式证实:
DROP ROLE
我们将通过从pg_hba.conf文件中删除sammydb数据库的主机条目来完成清理,因为我们不再需要它:
sudo nano /etc/postgresql/9.5/main/pg_hba.conf
从pg_hba.conf中删除的行
host  sammydb  sammy   client_ip_address/32   md5
为了使更改生效,我们将保存并退出,然后重新启动数据库服务器:
sudo systemctl restart postgresl
为确保成功重新启动,我们将检查状态:
sudo systemctl status postgres
如果我们看到“活动:活动”,我们将知道重新启动成功。 在这一点上,我们可以在需要远程连接的客户端上配置应用程序或服务。

其他安全注意事项

本教程旨在减轻允许不安全的远程连接到PostgreSQL所带来的风险,这是一种常见的情况,即无意中将PostgreSQL暴露给exploit。将对监听端口的访问限制为特定主机不会解决其他重要的安全问题,例如如何在传输中加密数据。 在使用实际数据之前,我们建议您查看以下资源,并针对您的用例采取适当的步骤。
  • PostgreSQL中的安全性 :GRANT语句确定允许哪些用户访问任何特定数据库,而角色建立这些用户的特权。在组合中,它们在单个安装中提供多个数据库之间的分离。
  • 使用PostgreSQL设置SSL :配置SSL将加密传输中的数据。这可以在发送数据时保护数据。
  • 使用SSH隧道保护PostgreSQL TCP / IP连接 :当与不支持SSL的客户端连接时,SSH隧道很有用。在几乎任何其他情况下,最好使用Postgres设置SSL。

结论

在本教程中,我们已经采取了一些基本步骤,通过配置服务器的防火墙以允许仅需要需要访问的主机的连接,并通过将PostgreSQL配置为只接受来自这些主机的连接,来防止广告我们的PostgreSQL安装。这减轻了某些类型的攻击的风险。这只是确保数据安全的第一步,我们建议您检查并实施上述其他安全措施。