我的两个站点都有 HAProxy,其中一个是公共的,一个是私有的。
www.mysite.com private.mysite.com
Atm,我正在使用这样的 haproxy:
frontend mysite_https
bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3
mode http
acl domain_www hdr_beg(host) -i www.
acl domain_private hdr_beg(host) -i private.
acl path_ghost path_beg /ghost/
acl clientcert ssl_c_used
redirect location https://www.example.com if path_ghost !clientcert
redirect location https://www.example.com if !domain_www !clientcert
use_backend bknd_private if domain_private
use_backend bknd_www if domain_www
default_backend bknd_www
这应该做的是要求客户证书(可选)并继续。如果域不是 www.example.com 且访问者无法提供正确的证书或路径为 /ghost/ 且访问者无法提供正确的证书,则应重定向到https://www.example.com
到目前为止,这工作正常。但是,Mac 用户使用 Safari 浏览我的网站时抱怨说,他们在浏览https://www.example.com/时不断被要求提供证书,而例如 Firefox 仅在浏览https://private.example时询问.com/或https://www.example.com/ghost/。
显然这就是 Safari 的工作方式,所以我无法解决这个问题。我的想法是使用 SNI 来划分不同的前端
frontend mysite_https
bind *.443 ssl crt /etc/mycert.pem no-sslv3
frontend private_https
bind *.443 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3
当然这不起作用,因为
一个。我不能让两个前端监听端口 443,而只有一个公共 IP b。我还没有找到一种方法来说“use_frontend if domain_www”或类似的东西。(仅 use_backend 或 use-server)
我也试过用三个 haproxy 服务器来做
frontend haproxy-sni
bind *:443 ssl crt /etc/mycert.pem no-sslv3
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req.ssl_hello_type 1 }
acl domain_www ssl_fc_sni_end -i www.example.com
use-server server1 haproxy-private.lan if !domain_www
use-server server2 haproxy-public.lan if domain_www
这行得通,但是这里的问题是 haproxy-private 请求客户端证书,但请求没有到达浏览器。不知何故,haproxy-sni 放弃了请求。
此外,我现在有三个不可取的 haproxy 服务器(尽管如果我找不到更好的解决方案,这是一个可能的选择)。
最好我想要这样的东西(编造..不知道真正的选择)
frontend mysite_https
bind *.443 ssl crt /etc/mycert.pem no-sslv3
mode http
acl domain_www hdr_beg(host) -i www.
acl domain_private hdr_beg(host) -i private.
acl path_ghost path_beg /ghost/
ssl_options ca-file /etc/myca.pem verify optional if !www_domain # made up!
ssl_options ca-file /etc/myca.pem verify optional if !path_ghost # made up!
acl clientcert ssl_c_used
redirect location https://www.example.com if path_ghost !clientcert
redirect location https://www.example.com if !domain_www !clientcert
...
我希望有人可以帮助我解决这个问题...
我找到了解决这个问题的方法,不需要额外的服务器或服务。我不完全确定这是否不会产生新问题。对我来说,它现在似乎有效。
我这样做的方式是为需要不同 ssl 设置的每个域创建一个前端。然后我将这些前端的绑定选项设置为高端口(公共无法访问这些端口!)。
我创建了另一个在端口:443 上侦听的前端,以根据 SNI 划分流量,并将后端服务器设置为 127.0.0.1:high-port。
这样,我在 haproxy 中创建了一个循环
这是配置部分。
如果有人对此有想法,或者知道为什么这可能是个坏主意,请告诉我。它有效,但我想知道为什么 use_frontend 不是一个选项。也许是因为无论出于何种原因,这是不应该做的事情。
最新版本的 haproxy 支持一个名为的设置
crt-list
,允许您根据匹配的证书指定不同的 TLS 设置你可以像这样使用它:
haproxy.conf:
crt-list.conf:
更多信息:https ://cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list
关于安全性的注意事项:始终将您的(敏感)主机名与 SNI 匹配
ssl_fc_sni
,而不是 HTTP 主机名。否则,攻击者可能会通过发送 TLS SNI 来绕过您的客户端证书身份验证,www.example.org
但将 HTTP 主机名设置为private.example.org
!