按服务器证书列入白名单的出站代理?

信息安全 tls 代理人 白名单 渗出
2021-08-17 23:10:33

简洁版本:

您是否知道任何代理或防火墙设备仅允许与具有批准* SSL 证书的主机进行出站 SSL 连接?

长版:

考虑以下场景。

我有一个服务器场,它通过防火墙保护免受 Internet 的影响。假设 HTTPS 允许从 Internet 进入,但防火墙阻止了从这些计算机到 Internet 的出站访问。我不希望我的服务器管理员感到无聊并浏览 /. 来自数据中心,我不希望恶意软件或恶意行为者能够在发生违规时轻松连接出站。

不过,我确实想允许一些出站访问。例如,假设我希望我的 Windows 服务器访问 windowsupdate.microsoft.com。如果我能确定windowsupdate使用的IP,没问题,我专门在防火墙里打开,没问题。

但是,如果这些 IP 不为人所知或不可知怎么办?具体来说,假设 Microsoft 正在使用 Akamai 或其他CDN来提供他们的文件。您联系的 IP 地址将很难提前确定,并且会定期更改。在这种情况下,我不能按 IP 列入白名单。

一种优雅的解决方案 - 假设我们正在访问受 SSL 保护的服务 - 是基于 SSL 证书而不是 IP 地址来列入白名单。因此,如果服务器证书是 *.windowsupdate.microsoft.com 并且由有效的 CA 签名,则允许连接。如果不是 *.windowsupdate.microsoft.com,或者它是由 SnakeOil 签名的,则禁止连接。

批准的证书可能意味着任何数量的灵活事物。名称和受信任的 CA;名称和特定的 CA;特定的 CA 签名证书;等等)

控制点不能位于内部服务器 - 如果恶意行为者获得访问权限,他们必须无法禁用此保护。与 IP 白名单一样,删除对外围的控制作为代理或防火墙设备是有意义的。

在我看来,这似乎是正确的做法。我这样做的选择是什么?这是任何人都曾经实施过的范式,是免费的还是商业的?我应该知道他们的其他范例是否可以以灵活但强大的方式限制传出访问,以满足现代(Akamai、AWS、Dyn-ish)动态服务?

任何帮助表示赞赏!

4个回答

我能想到两件事,既不完全符合要求,又需要一些组装。

  1. squid 使用sslBumpSSL 服务器证书验证器 这基本上是一个 MITM SSL 代理配置,您可以提供一个外部“帮助器”来增强正常验证。绊脚石包括证书信任和管理您自己的 CA/证书。我从来没有用过这个。

  2. Apachehttpd作为转发代理,带有mod_rewritemod_proxy外部验证脚本。这里的方法是在允许访问之前使用mod_rewrite 程序映射来预先验证目标的证书。

可以轻松测试 Apache 选项: httpd.conf

LoadModule proxy_module           modules/mod_proxy.so
LoadModule proxy_connect_module   modules/mod_proxy_connect.so
LoadModule rewrite_module         modules/mod_rewrite.so
[...]
Listen 10.0.0.16:3128

<VirtualHost 10.0.0.16:3128>
    ServerName   proxy.domain.com
    ErrorLog  ...
    CustomLog ...

    ProxyRequests on
    RewriteEngine on

    RewriteMap sslval prg:/usr/local/apache2/bin/sslval

    <Proxy>
        RewriteEngine on

        ## parse CONNECT
        RewriteCond %{THE_REQUEST} "^(CONNECT) ([^:]+)(:([0-9]+))? HTTP/"   [NC]
        RewriteRule .          -   [env=CHOST:%2,env=CPORT:%4]

        ## hand over to sslval
        RewriteCond  ${sslval:%{ENV:CHOST}:%{ENV:CPORT}}          ok
        RewriteRule  .                            -               [P,L]

        RewriteRule   .                           -               [F]

    </Proxy>
</VirtualHost>

这是一个外部“sslval”脚本,gnutls-cli由于其证书缓存支持而使用,并允许您准确指定您期望的证书:

#!/bin/bash
export HOME=/usr/local/apache2
while read key; do
    timeout 10 gnutls-cli --tofu \
        --port=${key##*:}  ${key%%:*}  >/dev/null 2>&1 <<<Q
    [ $? = 0 ] && echo ok || echo fail
done

现在您需要做的就是将预期的证书添加到与~apache/.gnutls/known_hosts交互gnutls-cli --tofu ...,然后输入“y”进行确认。

这种对首次使用的信任方法可能看起来很熟悉,它与 OpenSSH 的known_hosts. 这种方法与OpenVPN 的 --tls-verify选项没有什么不同。

脚本的变体sslval可用于检查选定的 CA 数据库,例如使用 OpenSSLs_client.pemCA 文件数据库(使用 维护c_rehash),例如:

timeout 10 openssl s_client \
         -connect "$key" -servername "${key%%:*}" \
         -verify 5 -CApath /usr/local/etc/CA <<< Q |
   gawk '/Verify return code: (19|0) /{ok=1} 
      END{print ok?"ok":"fail"}'

错误检查、锁定、配置和访问控制、缓存以及所有这些好东西都是读者的练习...... ;-)

对于 Apache (2.2.2x),我发现代理正常请求(非 CONNECT)会受到上述 mod_rewrite 技术的影响,您将需要第二个 VirtualHost。

正如 Spuratic 先生解释的那样,您可以使用 SSL 终止代理按证书进行过滤。

但是,将 SSL 直通代理转换为 SSL 终止代理是一件大事,而不是纯粹为了您概述的动机而做的事情。

您最好的实用选择是按主机名过滤。

Blue Coat ProxySG 可以完成大部分(如果不是全部)。

如果我正确理解这一点,那么您希望防范基于 DNS 中毒和证书伪造的攻击风险。

squid 先生描述的 Squid 方法的问题是您将伪造的证书发送回客户端 - 在守护进程的情况下,它应该拒绝连接,而浏览器将显示丑陋的警告消息(并且无法连接到实施 HSTS 的站点),除非您还在客户端上安装了蛇油 CA 证书——从安全的角度来看,这可能不是一个好主意。

如果我想实现这个,那么我可能会使用一个自定义代理,我可以在从解析的 IP 地址轮询服务器证书时暂停 CONNECT 请求(很容易编写 openssl 脚本来检索和操作证书) . 这似乎是 sprapatic 先生继续使用 Apache 描述的内容 - 但我对 mod_rewrite/gnutls 不够熟悉,无法说出是否是这种情况/他的方法是否有效。

除此之外,还需要满足证书到期的需要,以及对于特定主机名(特别是对于像 Microsoft 这样的大型组织)可能存在多个有效证书的可能性,这开始看起来像是一个相当复杂的练习。

我的第一个想法是,专注于保护 DNS 数据而不是对证书进​​行更广泛的验证可能更有效。一个明显的解决方案是使用 DNSSEC,但我看到虽然微软提供了 DNSSEC 客户端支持,但似乎并没有在他们的服务器上实现

也许更实际的解决方案是在本地维护相关主机的 DNS 数据比它们的 TTL 长得多?