如何保护开放的PostgreSQL端口


29

所以,这就是情况。看来我们需要有一个通向世界的开放TCP端口5432,客户可以在其中访问他的PostgreSQL数据库。

由于明显的原因,我们不能说“不”,只能说是最后的手段。

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

无论如何:为什么向世界开放?我认为,也许它比大约20年未维护的FTP服务器更安全。

PS VPN不好。一些加密可能(如果我可以给他其中JDBC连接URL 的作品)。


4
SSH隧道不是一种选择吗?该how-to文章实际上以PostgreSQL为例。您可以为客户提供预配置的SSH客户端,以使其易于连接。
路西法·萨姆

@LuciferSam号。数据库将由内部开发的Java应用程序在大约100个公司机器上使用。我们配置它们的唯一方法是将jdbc连接URL赋予其localnet管理,其他任何问题都非常棘手。

@milkman应用程序做什么?也许它可以查询RESTful服务器呢?显然,通过SQL以REST不会获得任何东西,但假设它是CRUD ..
tedder42

@ tedder42它也处理由我们托管的用户CMS的数据库。我们无权更改其来源。

Answers:


41

需要SSL,保持SELinux处于打开状态,监视日志并使用当前的PostgreSQL版本

服务器端

需要SSL

postgresql.confssl=on,并确保你有你的密钥文件和certFile中适当地安装(请参阅该文档,并在注释postgresql.conf)。

如果想让客户端信任证书而无需在客户端上进行特殊设置,则可能需要从CA购买证书。

pg_hba.conf使用这样的:

hostssl theuser thedatabase 1.2.3.4/32 md5

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

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

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

限制用户权利

限制用户(一个或多个),可以登录的权利。不要给他们CREATEDBCREATEUSER权利。

REVOKE您可以访问所有数据库上的CONNECT权限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指向其密钥库,因此它不是完全透明的。

隔离实例

如果您想真正地偏执,请在单独的容器/ VM中或至少在不同的用户帐户下运行客户端实例,并仅使用它们所需的数据库。

这样,如果他们危及PostgreSQL实例,他们将一无所获。

使用SELinux

我不必这么说,但是...

运行支持SELinux的计算机,例如RHEL 6或7,请勿关闭SELinux或将其设置为许可模式。使其处于强制模式。

使用非默认端口

仅凭一无所知的安全就是愚蠢。完成明智的操作后,使用一点点晦涩的安全性可能不会受到伤害。

在非默认端口上运行Pg会使自动攻击者的生活更加艰难。

放在代理前面

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

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


3
如果客户端具有静态$ IP,则仅允许它通过防火墙到达$ port。
user9517支持GoFundMonica 2014年

非常感谢你!Pgjdbc具有此参数,但是我只能给他一个jdbc连接URL,而且我不确定它是否可以与他的Java应用程序一起使用(专有的,不可破解的)。好吧,否则我会问一个新问题。谢谢您的详细回答!

1
@lesto实际上,与仅提供一项受限服务相比,我认为公开VPN会大大增加攻击面。人们忘记了VPN然后成为远程计算机上任何恶意软件的攻击渠道,以突破所有外围安全问题并进入网络的胆量。我只有在它们连接到DMZ并将它们视为与Internet主机一样有毒的DMZ时才认为它们可以接受。
Craig Ringer 2014年

1
@CraigRinger我并不是要删除其余的保护,而是将服务封装到VPN中
Lesto

1
@lesto当然,同意,如果不幸的是,VPN没有像许多管理员一样被视为Magic Security Sauce,则VPN可以是一个有用的额外层。
Craig Ringer 2014年

2

克雷格斯令人印象深刻的行动计划的简单扩展:

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

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

一个简单的支持方案:

  1. 您的客户称您为“我无法登录”
  2. 您可以通过tcpdump -i eth0 -p tcp port 5432命令找到他来自哪里。
  3. 使用a,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规则集。(针对“ uif iptables”的Google)。


1
有趣的想法,但这听起来有些脆弱。
nishantjr 2014年

@nishantjr当然,这不是一个独立的解决方案,只能使事情变得更好。
彼得说恢复莫妮卡2014年

更实际的方法可能是白名单个人互联网服务供应商和/或国家,各种方法来做到这一点看如stackoverflow.com/questions/16617607/...
约瑟普·罗丹

1

这是一个基于以上HOWTO的PostgreSQL的相当简单的Fail2ban配置,但已进行了微调,可以实际与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

1

Fail2ban是一个功能强大的工具,但不要相信过滤器会照常工作。使用failregex工具测试所有过滤器,并记住转义任何引号(即“ admin”为\“ admin \”)。例如,从我的/etc/log/postgresql/postgresql-9.3-main.log测试以下过滤器failregex行对我不起作用。

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' '<HOST>\(\d+\) FATAL:  password authentication failed for .+$'

以上给了我

Failregex:总计0

我必须更新failregex以匹配日志格式。

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' 'FATAL:  password authentication failed for user \"<HOST>\"'

这给了我积极的结果。

Failregex:总共1个

fail2ban-regex测试也可以在整个日志文件上实现。

fail2ban-regex /var/log/postgresql/postgresql-9.3-main.log /etc/fail2ban/filter.d/postgresql.local

以上通过更新的failregex给了我以下积极的结果。

Failregex:总计169

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.