有没有什么办法可以配置没有公共证书的 Nginx?
这里的目标是,我想在公共互联网上发布一个 API,但所有 API 客户端(白名单客户端)都应该在其应用程序中通过 SSL 锁定公共证书,而不是根据请求临时获取证书。所以我们不需要 nginx 来发布公共证书。
我知道公开共享公共证书是无害的,但这个奇怪的请求来自我们的企业客户。他们甚至询问我们是否可以在 nginx 中放置无效的公共证书……因此,当没有真正的公共证书的“攻击者”将 API 视为错误时,而真正的 ssl-pinned 客户端将能够正常使用该 API。
答案1
从技术角度来看,你提出的问题(以及解释)并没有多大意义。我可以提出一些希望对你有帮助的陈述 -
要配置没有公共证书的 NGinx,您可以使用 HTTP(即放弃加密)。HTTPS 是围绕公私加密设计的,因此 Nginx 不使用它是没有意义的。
您可以创建自签名证书,然后让用户“固定”该证书。您还可以使用自签名 CA 证书创建自己的 CA,以便颁发多个证书。
您的企业客户不知道他们不知道多少。攻击者只需接受无效证书并继续。证书会加密浏览器和服务器之间的会话 - 如果浏览器没有公共证书,它不会阻止浏览器访问内容,也不意味着服务器可以信任客户端。
如果你想提高安全性,请查看客户端证书。这几乎与您所谈论的证书类型相反。实际上,您运行自己的 CA,并签署公钥 - 然后要求在客户端与您通信时使用这些密钥(大多数浏览器都支持这一点,但要让您考虑部署并不容易 - 虽然它非常实用)这基本上向服务器验证了客户端。如果客户端都通过 API 进行通信 - 这不是 API 的常见做法,应该告诉您一些事情 - 为什么不直接使用常规 HTTPS 证书然后使用共享密钥?
答案2
... 但所有 API 客户端(白名单客户端)都应在其应用程序内通过 SSL 锁定公共证书,而不是根据请求临时获取证书。因此,我们不需要 nginx 发布公共证书。
如果服务器不提供证书,则无法进行基于证书的服务器身份验证。这包括在客户端中锁定证书 - 这需要服务器也发送证书,以便根据锁定的证书进行验证。
可以让 nginx 使用自签名证书或私有 CA 颁发的证书。这没什么特别的,只需配置此证书即可。当客户端仅检查是否提供特定证书时,此自签名证书可能不包含任何真实信息(如主题等),它确实需要包含公钥(尽管匹配私钥)。
他们甚至询问我们是否可以在 nginx 中放置无效的公共证书……因此当没有真正的公共证书的“攻击者”将看到 API 为错误时,真正的 ssl-pinned 客户端将能够正常使用该 API。
除非在 TLS 握手期间发送证书之前能够区分客户端,否则不可能将一个证书提供给某些客户端(好客户端),而将另一个证书提供给其他客户端(坏客户端)。这种区分可以仅基于 TCP 信息(如源 IP 地址)进行。或者,客户端可以在 SNI 中使用一些隐藏的非公共域名(即与 DNS 查找中使用的域名不同),该域名与 nginx 中的不同配置相匹配。
答案3
这里的目标是,我想在公共互联网上发布一个 API,但所有 API 客户端(白名单客户端)都应该在其应用程序中通过 SSL 锁定公共证书,而不是根据请求临时获取证书。所以我们不需要 nginx 来发布公共证书。
服务器证书实际上并不参与设置 TLS 加密。它的唯一目的是核实已建立的连接——TLS 确实可以在没有证书的情况下工作,并且不会停止攻击者根本无法建立连接。所以这个计划行不通;从技术上讲是可以实现的,但毫无用处。
(可能是你的客户记得旧版 SSL 和 TLS 的工作方式;它以前是将证书的 RSA 密钥直接用作 TLS 密钥交换的一部分是一种很常见的做法;但多年来它一直不是这样运作的。TLSv1.3 甚至不再有这个选项了。)
他们甚至询问我们是否可以在 nginx 中放置无效的公共证书……因此当没有真正的公共证书的“攻击者”将看到 API 为错误时,真正的 ssl-pinned 客户端将能够正常使用该 API。
出于上述原因,这也是完全无用的。攻击者不会需要首先检查证书——错误的证书可能会被 TLS 客户端忽略。
(事实上,你可以提醒客户,当他们访问证书过期的网站并点击“忽略证书”时,他们自己可能也这样做过……虽然这是并不真地同样的事情——在这种情况下证书在技术上是有效的——您的客户可能无法分辨出差异,因此它可能仍然可以传达出要点。)
您可以使用两个有效选项:
使用客户证书,也称为“移动TLS“ – 这是限制访问 API 的常见选择。这将要求每个 API 客户端都有自己的证书,发送发送到服务器,并经过验证由服务器(由客户端使用自己的私钥提供证明)。告诉您的客户,这是实际银行用于其支付 API 的内容。
使用相移键控身份验证,这是 TLSv1.3 中的有效选项,并且根本不使用证书。(我思考在 TLSv1.2 中,它可能也是一个有效的选项,但据我所知,TLSv1.3 中发生了一些变化,使得 PSK 在该版本中更加可行。)在此模式下,客户端和服务器共享一个类似于用户名和密码的信息(“PSK 身份”和 PSK 本身),但与常规密码不同的是,PSK是实际上涉及建立加密——如果不提供有效的 PSK,就不可能建立 TLS 连接。
答案4
免责声明:如果我的答案有效,则涉及破坏标准 TLS。我只会使用自定义 HTTP 客户端。
不讨论你的方法的优点(其他答案已经这样做了),我想知道... 你不能“简单地”提供一个不同的证书,其中一个公钥不是与你的私钥匹配的证书。如果你尝试这样做,可能会有某种机制阻止 nginx 工作。并且你必须确保在你的客户端上可以设置 HTTP 堆栈以完全忽略服务器发送的证书并改用你的内置证书。
我对 TLS 并没有很深入的了解,但我“想象”用于加密流量(例如使用 ECDH)的加密密钥将使用来自服务器的公钥进行协商,该公钥(我相信)包含在证书中。
因此,客户端使用服务器发送的证书中的公钥建立加密通道将会失败,因为服务器上的私钥与证书中的公钥不匹配。