服务器端

服务器端

情况就是这样。看来我们需要向外界开放一个 TCP 端口 5432,以便客户可以访问他的 PostgreSQL 数据库。

出于显而易见的原因,我们不能仅仅说“不”,这只能作为最后的手段。

最大的麻烦是什么?我该如何捍卫我们的基础设施?

无论如何:为什么不应该它会向世界开放吗?我想,也许它比一些有 20 年历史、无人维护的 FTP 服务器更安全。

PS VPN 不行。有些加密或许(如果我可以给他一个 JDBC 连接 URL,作品)。

答案1

要求 SSL、保持 SELinux 处于开启状态、监控日志,以及使用当前 PostgreSQL 版本

服务器端

需要 SSL

设置并确保您已正确安装了密钥文件和证书文件(请参阅文档和中的注释postgresql.conf)。ssl=onpostgresql.conf

如果您希望获得客户端的信任并且无需在客户端进行特殊设置,则可能需要从 CA 购买证书。

pg_hba.conf使用中类似:

hostssl theuser thedatabase 1.2.3.4/32 md5

...可能对用户和/或数据库使用“全部”,并且可能使用更广泛的源 IP 地址过滤器。

限制可以登录的用户,拒绝远程超级用户登录

如果可能的话,不要允许用户“全部”登录;如果可以避免的话,您不想允许超级用户远程登录。

限制用户权限

限制可以登录的用户的权限。不要给予他们CREATEDB权限CREATEUSER

REVOKECONNECT在所有数据库上授予权限,PUBLIC然后将其仅归还给应该能够访问该数据库的用户/角色。(将用户分组为角色并将权限授予角色,而不是直接授予单个用户)。

确保具有远程访问权限的用户只能连接到他们需要的数据库,并且只对他们实际需要的架构、表和列拥有权限。这对本地用户来说也是一种很好的做法,这只是明智的安全措施。

客户端设置

在 PgJDBC 中,传递参数ssl=true

要指示 JDBC 驱动程序尝试建立 SSL 连接,您必须添加连接 URL 参数 ssl=true。

...并在客户端的信任库中安装服务器证书,或者如果您不希望用户必须安装证书,则使用 Java 内置信任库中的其中一个 CA 信任的服务器证书。

持续行动

现在确保 PostgreSQL 保持最新。PostgreSQL 仅有几个预先认证安全漏洞,但数量远大于零,因此请保持最新状态。无论如何,您都应该这样做,修复错误是一件好事。

如果有大型网络块/区域且您知道永远不需要访问,请在前面添加防火墙。

记录连接和断开连接(见postgresql.conf)。记录查询(如果可行)。如果可行,在前面运行入侵检测系统或 fail2ban 或类似系统。对于 postgres 的 fail2ban,有一个方便的操作方法这里

监视日志文件。

奖金偏执

需要考虑的额外步骤...

需要客户端证书

如果需要,您还可以使用pg_hba.conf来要求客户端提供服务器信任的 X.509 客户端证书。它不需要使用与服务器证书相同的 CA,您可以使用自制的 openssl CA 来执行此操作。JDBC 用户需要将客户端证书导入他们的 Java 密钥库,keytool并可能配置一些 JSSE 系统属性以将 Java 指向他们的密钥库,因此它不是完全透明的。

隔离实例

如果您真的想要谨慎,请在单独的容器/虚拟机中或至少在不同的用户帐户下为客户端运行实例,并且仅使用他们需要的数据库。

这样,如果他们破坏了 PostgreSQL 实例,他们就无法再取得任何进展。

使用 SELinux

我不应该这么说,但是......

运行支持 SELinux 的机器,如 RHEL 6 或 7,并且不要关闭 SELinux 或将其设置为宽容模式. 保持其处于强制模式。

使用非默认端口

安全保障仅有的模糊性是愚蠢的行为。一旦您采取了明智的措施,使用一点模糊性的安全性可能不会造成任何损害。

在非默认端口上运行 Pg,使自动攻击者的攻击变得更加困难。

把代理放在前面

您还可以在 PostgreSQL 前面运行 PgBouncer 或 PgPool-II,充当连接池和代理。这样,您就可以让代理处理 SSL,而不是真正的数据库主机。代理可以位于单独的 VM 或机器上。

无论如何,使用连接池代理对于 PostgreSQL 来说通常都是一个好主意,除非客户端应用程序已经有内置池。大多数 Java 应用程序服务器、Rails 等都有内置池。即便如此,服务器端池代理在最坏的情况下也是无害的。

答案2

对 Craigs 令人印象深刻的行动计划进行简单扩展:

也许用户仅使用一组相对较少的网络提供商(例如,他在移动时的移动网络提供商、他家里的有线网络和工作场所的传出 IP)。

大多数网络提供商都有很多 IP,但实际上没有很多子网。因此,您可以提供一个 iptables 过滤器,将 postgresql 访问限制到您的客户使用的网段。这大大降低了随机选择的网络故障源攻击的可能性。

简单的支持场景:

  1. 你的客户给你打电话,“我无法登录”
  2. 你可以通过命令来发现tcpdump -i eth0 -p tcp port 5432他是从哪里来的。
  3. 使用whois 1.2.3.4可以获取此 ip 使用的 ip 地址。例如,它可以是1.2.3.0/24
  4. 使用iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT(或类似的)您允许与他的新子网建立 TCP 连接。

有一个名为的非常好的 perl 脚本uif,它可以提供永久且直观的可声明 iptables 规则集。(Google 搜索“uif iptables”)。

答案3

这是一个相当简单的 PostgreSQL Fail2ban 配置,基于上面链接的 HOWTO,但经过微调以实际与 Ubuntu 软件包一起使用,捕获另一种错误情况并跳过各种调试消息以使其更快:

/etc/fail2ban/filter.d/local-postgresql.conf

[Definition]

failregex = <HOST>\(\d+\) FATAL:  password authentication failed for .+$
            <HOST>\(\d+\) FATAL:  no pg_hba.conf entry for host .+$

ignoreregex = duration:

/etc/fail2ban/jail.d/local-postgresql.conf

[local-postgresql]
enabled  = true
filter   = local-postgresql
action   = iptables[name=PostgreSQL, port=5432, protocol=tcp]
           sendmail-whois[name=PostgreSQL, dest=root@localhost]
logpath  = /var/log/postgresql/postgresql-9.3-main.log
maxretry = 3

答案4

我在配置时遇到问题失败2ban因为默认 PostgreSQL 日志配置中缺少 IP 地址。我在 Debian 10 上使用 PostgreSQL 12 和 13。所以如果有人遇到同样的问题,这里是如何修复它。

/etc/postgresql/13/main/postgresql.conf

log_line_prefix = '%m {%h} [%p] %q%u@%d '

默认值为:'%m [%p] %q%u@%d '。我添加了%h将 IP 地址传递给 fail2ban。

/etc/fail2ban/filter.d/postgresql.conf

[Definition]
failregex = \{<HOST>\} .+? FATAL:  password authentication failed for user .+$

/etc/fail2ban/jail.d/postgresql.conf

[postgresql]

enabled = true
filter = postgresql
logpath = /var/log/postgresql/postgresql*.log
maxretry = 3
bantime = 86400
port = 5432

然后重新启动fail2ban服务systemctl restart fail2ban

并查看日志tail -f /var/log/fail2ban.log

相关内容