我有一台运行多个虚拟主机的服务器。 其中一些网站具有SSL组件,而其他网站则没有。 今天我注意到,如果我尝试通过https访问其中一个非SSL站点,Nginx会发现一个虚拟主机, 它使用SSL并尝试呈现它 – 在此之前给出熟悉的“不可信”警告。
我已经尝试了几种解决scheme,但都没有工作,我已经用尽了我的Nginx知识和/或阅读理解。 理想情况下,我想看到一个404错误,如果一个网站是通过它不支持的协议访问。
我尝试了各种编辑到default服务器块,但没有工作。 我也尝试捕获和redirect端口443访问该特定的网站,但(可预测)也失败了。
有人能指出我正确的方向吗?
没有可以做的。 没有服务器名称指示(SNI),主机名是encryption的有效负载的一部分。 即使使用SNI,浏览器也不会接受来自HTTPS URL的redirect,而无需先通过HTTPS握手+validation过程。
如果你愿意的话,你可以使用两个IP地址,一个用于你的安全站点,一个用于非安全站点,并且只能在安全IP上收听443。
你可以通过添加一个伪造的服务器条目(我使用自签名的本地主机)ssl证书来返回你想要的错误。 这应该是第一个服务器块,或者至less在任何其他ssl块之前。 请注意,我通常使用拒绝所有,但在这种情况下,添加404。
server { listen 443 ssl default_server; server_name localhost; ssl_certificate_key /etc/ssl/private/localhost.key; ssl_certificate /etc/ssl/certs/localhost.crt; # deny all; return 404; }
要生成自签名证书,您可以使用以下命令
openssl genrsa 4096 > localhost.key openssl req -new -sha256 -key localhost.key -subj "/CN=localhost" > localhost.csr openssl x509 -req -days 3650 -in localhost.csr -signkey localhost.key -out localhost.crt chmod 600 localhost.key mv localhost.key /etc/ssl/private/ mv localhost.crt /etc/ssl/certs/
我不认为其他答案涵盖了整个故事:
由于SNI,你想要做的事情是服务器可以做的。 但是,即使它支持SNI,nginx也不支持你想做的事情。 nginx将对待一个不匹配的SNI名称,就好像它是用于默认的SSL站点一样(并且如果您没有标记SSL站点作为您的默认站点,则是其configuration中的第一个SSL站点)。 这通常会导致用户看到证书警告通知,因为证书nginx发送的名称与客户端请求的名称不匹配。
SNI的RFC规定,服务器可能认为一个无法识别的SNI名称是致命的:
如果服务器了解客户端的hello扩展名,但不能识别服务器名称,它应该发送“unrecognized_name”警报(这可能是致命的)。
但是据我所知,Apache和nginx都继续进行连接,并以与处理不匹配或丢失的“Host:”标题相同的方式处理它,即select标记为默认的虚拟主机地址:端口。
除非您已经获得了与客户端在联系您的服务器时可能使用的每个可能的域名相匹配的SSL证书,否则在继续之前无法阻止用户看到关于无效证书的警告。 即使您一到网站就redirect,只有在无效证书被接受后才会处理。
2017更新:因为现在您可以轻松获得所有域名的免费SSL证书,即使您不打算通过HTTPS为其提供实际内容,也可以获得所有域名的SSL证书,以确保任何redirect或错误消息将在没有任何关于不匹配证书的警告的情况下运行
NGinx是不可能的(或者默认情况下,与其他任何东西)。
如果您完全不关心较旧的客户端(例如在Windows XP上使用Chrome或IE),并且您确实只支持使用TLS协议的SNI扩展的客户端,那么您可以在nginx前面使用haproxy来执行这个。
另一个解决scheme是将所有非SSL网站放在一个完全独立的IP地址上,这个地址在https端口上没有监听。
我不确定你尝试了什么,但如果你有SNI的支持,一种方法是形成一个全面的:
server { listen [::]:443 default_server ssl; listen 443 default_server ssl; server_name _; return 444; } server { listen [::]:443 ssl; listen 443 ssl; server_name ssl.site.net; ssl_certificate your.crt; ssl_certificate_key your.key; ....etc...
这将转储不匹配的服务器(从我曾经使用的configuration,我目前没有,所以申请粮食盐)正如其他人指出的,我不相信你可以做这样的redirect,只有一个下降。
对于非SNI的支持(阅读:遗留),你总是可以获得通配符低价证书,那么你将能够处理所有的连接和redirect的愿望没有问题。
编辑:第二个想法,如果我记得,因为nginx支持SNI,即使不支持SNI的客户端连接,它仍然会导致nginx return 444而尝试匹配证书发送…想法?