nginx proxy_pass 带有后端请求客户端证书

nginx proxy_pass 带有后端请求客户端证书

我们正在代理一个我们无法控制的后端,并且后端在 https 上连接时正在请求客户端证书。

当我们通过代理请求这些页面时,连接超时,后端没有响应,但是如果我们绕过代理,页面就可以正常工作。这是 nginx 处理客户端证书的问题吗?还是我们应该在其他地方寻找?

Nginx 配置:

server {
        listen 443 ssl;

        ssl on;
        ssl_certificate /etc/nginx/ssl/webserver.pem;
        ssl_certificate_key /etc/nginx/ssl/webserver.key;

        location / {
                 proxy_pass https://www.backendsite.com;
                 proxy_set_header X-Forwarded-For $http_x_forwarded_for;
        }
}

答案1

我不确定您是否意识到了这一点,但您正在做的是对的中间人攻击www.backendsite.com

要理解为什么这在您的场景中行不通,我们需要解释证书和密钥在 TLS 中的实际作用。让我们开始吧。

首先,我们需要建立一个明文密钥。我们没有安全通道,而且出于效率原因,我们也不能有安全通道,所以我们使用 Diffie Hellman 作为密钥交换协议。以前我们可能已经建立了使用的参数。现代思想认为这是一个坏主意,让我们边走边想。这称为 DHE(Ephemeral Diffie Hellman)。如果您真的很喜欢,您可以通过 EC(EC-DHE)来实现这一点。

现在的问题是,你怎么知道我使用 DH 向您发送了参数吗?为了验证这一点,我们需要一个数字签名算法,以便您可以获得一些关于我的公开信息,以验证使用我的私钥进行的签名只能由我进行。

服务器密钥材料为服务器端提供私钥和公钥(包含在证书中,以及 CA 的签名,表示“是”,我们也信任它)。

通常情况下,客户端可以按照自己的意愿为匿名连接生成公钥/私钥对。因此在通常情况下:

  • 客户端有任何旧的密钥对。
  • 她与您的代理建立了工作连接。流量通过此隧道进行加密/解密。
  • 代理有自己的“任何旧密钥对”,用于与服务器建立连接。
  • 服务器并不太关心客户端是谁,它会与任何人建立连接,因此它使用代理的公钥。
  • 会话已建立。

但是,现在客户端提供了特定的密钥对。该密钥对用于保护协议的参数,因此会发生以下情况:

  • 客户端有一个特定的密钥对,请求 TLS 并发送其参数和公钥。
  • 代理解密并可以以两种方式重新打包(我不知道其中哪一种会真正发生 - 取决于实现 - 我只是解释为什么这不起作用):
    • 它提供客户端的公共证书而不是自己的证书。由于没有私钥,它无法解密任何会话响应。
    • 因此,它会生气地(再次强调,这不是实际发生的事情,只是举例说明)并生成自己的证书。但是,服务器不会与除给定标准之外的证书对话(例如,由某个已知证书签名),因此拒绝协商连接。

这种方法之所以行不通,是因为 nginx 试图充当 http 代理,根据需要启动并重新应用 https,并且通过在两端建立受信任的证书,TLS 在设计上可以防止 MITM。

工程师可以采取一些替代的设计决策,让后端处于他们的控制之下。我最终选择这里是因为我希望代理到 unix 套接字,并向前传递一些证书信息。这可以使用这些笔记使用 nginx 进行证书验证这一观察在 HTTP 标头上(不要传递整个原始证书)。

相关内容