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