所以,这就是情况。看来我们需要有一个通向世界的开放TCP端口5432,客户可以在其中访问他的PostgreSQL数据库。
由于明显的原因,我们不能说“不”,只能说是最后的手段。
最大的麻烦是什么?我该如何捍卫我们的基础设施?
无论如何:为什么不向世界开放?我认为,也许它比大约20年未维护的FTP服务器更安全。
PS VPN不好。一些加密可能(如果我可以给他其中JDBC连接URL 的作品)。
所以,这就是情况。看来我们需要有一个通向世界的开放TCP端口5432,客户可以在其中访问他的PostgreSQL数据库。
由于明显的原因,我们不能说“不”,只能说是最后的手段。
最大的麻烦是什么?我该如何捍卫我们的基础设施?
无论如何:为什么不向世界开放?我认为,也许它比大约20年未维护的FTP服务器更安全。
PS VPN不好。一些加密可能(如果我可以给他其中JDBC连接URL 的作品)。
Answers:
需要SSL,保持SELinux处于打开状态,监视日志并使用当前的PostgreSQL版本。
在postgresql.conf
集ssl=on
,并确保你有你的密钥文件和certFile中适当地安装(请参阅该文档,并在注释postgresql.conf
)。
如果想让客户端信任证书而无需在客户端上进行特殊设置,则可能需要从CA购买证书。
在pg_hba.conf
使用这样的:
hostssl theuser thedatabase 1.2.3.4/32 md5
...对于用户和/或数据库,可能带有“全部”,并且可能具有更宽泛的源IP地址过滤器。
如果可能,不允许用户使用“全部”;您可以避免超级用户远程登录,如果您可以避免的话。
限制用户(一个或多个),可以登录的权利。不要给他们CREATEDB
或CREATEUSER
权利。
REVOKE
您可以访问所有数据库上的CONNECT
权限PUBLIC
,然后仅将其返回给应该能够访问该数据库的用户/角色。(将用户分组为角色,并授予角色权限,而不是直接授予单个用户)。
确保具有远程访问权限的用户只能连接到他们需要的数据库,并且仅拥有他们实际需要的架构,表和列的权限。这对于本地用户也是一个好习惯,这只是合理的安全性。
要指示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的计算机,例如RHEL 6或7,请勿关闭SELinux或将其设置为许可模式。使其处于强制模式。
仅凭一无所知的安全就是愚蠢。完成明智的操作后,使用一点点晦涩的安全性可能不会受到伤害。
在非默认端口上运行Pg会使自动攻击者的生活更加艰难。
您还可以在PostgreSQL之前运行PgBouncer或PgPool-II,充当连接池和代理。这样,您可以让代理处理SSL,而不是真正的数据库主机。代理可以位于单独的VM或计算机上。
无论如何,使用连接池代理通常是PostgreSQL的一个好主意,除非客户端应用程序已经具有内置池。大多数Java应用程序服务器,Rails等都具有内置池。即使这样,服务器端池代理在最坏的情况下也是无害的。
克雷格斯令人印象深刻的行动计划的简单扩展:
也许用户只使用了相对较少的一组网络提供商(例如,移动时他的移动网络提供商,他的有线网络从家里和工作场所传出的IP从工作中)。
大多数网络提供商都有很多IP,但实际上没有很多子网。因此,您可以提供一个iptables过滤器,该过滤器将postgresql访问限制为客户使用的网段。这大大降低了随机选择网络故障源的攻击可能性。
一个简单的支持方案:
tcpdump -i eth0 -p tcp port 5432
命令找到他来自哪里。whois 1.2.3.4
您可以获得该IP使用的IP地址。例如,可以是1.2.3.0/24
。iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT
(或类似的)命令,您可以将tcp与他的新子网连接。有一个非常好的perl脚本uif
,可以提供永久和直观的可声明iptables规则集。(针对“ uif iptables”的Google)。
这是一个基于以上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
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