我的两个站点都有 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
Run Code Online (Sandbox Code Playgroud)
这应该做的是要求客户端证书(可选)并继续。如果域不是 www.example.com 且访问者无法提供正确的证书或路径为 /ghost/ 且访问者无法提供正确的证书,则应重定向到https://www.example.com
So far, this works fine. However, I got complaints by Mac users browsing my site with Safari that they keep getting asked for the certificate when there browsing on https://www.example.com/ whereas for example Firefox only asks when browsing https://private.example.com/ or https://www.example.com/ghost/.
Appearently that's just how Safari works so I can't fix that. My idea was to use SNI to divide between different frontends
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
Run Code Online (Sandbox Code Playgroud)
Of course that doesn't work because
a. I can't have two frontends listening on port 443 with only one public IP b. I haven't found a way yet to say "use_frontend if domain_www" or something like that. (Only use_backend or use-server)
I also tried doing it with three haproxy servers
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
Run Code Online (Sandbox Code Playgroud)
This works, the problem here however is that haproxy-private asks for the client certificate, but the request doesn't reach the browser. Somehow haproxy-sni drops the request.
Also, I now have three haproxy servers which is not desirable (although a possible option if I can't find a better solution).
Preferably I would like something like this (made up.. don't know the real options)
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
...
Run Code Online (Sandbox Code Playgroud)
I hope someone can help me with this...
moh*_*ium 13
我找到了解决这个问题的方法,不需要额外的服务器或服务。我不完全确定这是否不会产生新问题。对我来说,它现在似乎有效。
我这样做的方法是为每个需要不同 ssl 设置的域创建一个前端。然后我将这些前端的绑定选项设置为高端口(公共无法访问这些端口!)。
我创建了另一个监听端口 :443 的前端以根据 SNI 划分流量,并将后端服务器设置为 127.0.0.1:high-port。
这样,我在 haproxy 中创建了一个循环
[incoming]->[haproxy:443]->[haproxy:7000]->[www.intern.lan]
[incoming]->[haproxy:443]->[haproxy:8000]->[private.intern.lan]
Run Code Online (Sandbox Code Playgroud)
这是配置部分。
frontend frnd_snipt # Frontend_SNI-PassThrough (snipt)
bind *:443 # Do not use bind *:8443 ssl crt etc....!
option tcplog
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl subdomain_is_www req_ssl_sni -i www.example.com
acl subdomain_is_www req_ssl_sni -i example.com
acl subdomain_is_private req_ssl_sni -i private.example.com
use_backend bknd_snipt_private if subdomain_is_private
use_backend bknd_snipt_www if subdomain_is_www
backend bknd_snipt_www
mode tcp # tcp mode must match the frontend mode - already set as default in [global]
server snipt-www 127.0.0.1:7000 # run without "check", otherwise haproxy checks itself all the time!
backend bknd_snipt_private
mode tcp
server snipt-private 127.0.0.1:8000 # also, don't add "ssl" when in tcp mode. "ssl" is an http mode option (result in "NO-SRV" when set in tcp)
##### NORMAL HAPROXY PART #####
frontend www_example_com # this frontend can be in tcp or http mode...
bind *:7000 ssl crt /etc/mycert.pem no-sslv3 # www. frontend with normal https
mode http
option httplog
frontend private_example_com
bind *:8000 ssl crt /etc/mycert.pem ca-file /etc/myca.pem verify optional no-sslv3 # private. frontend with client certificate request.
mode http
option httplog
... # whatever you have in your frontend
Run Code Online (Sandbox Code Playgroud)
如果有人对此有想法,或者知道为什么这可能是个坏主意,请告诉我。它有效,但我想知道为什么 use_frontend 不是一个选项。也许是因为无论出于何种原因都不应该这样做。
小智 5
最新版本的 haproxy 支持一个名为 的设置crt-list
,允许您根据匹配的证书指定不同的 TLS 设置
你可以这样使用它:
haproxy.conf:
frontend https
mode http
bind *:443 ssl crt-list /etc/haproxy/crt-list.conf ca-file ca.pem
use_backend test if { ssl_fc_sni -i test.area.example.org }
use_backend private if { ssl_fc_sni -i private.example.org }
default_backend www
Run Code Online (Sandbox Code Playgroud)
crt-list.conf:
www.pem [verify none]
www.pem [verify required] *.area.example.org
private.pem [verify required]
Run Code Online (Sandbox Code Playgroud)
更多信息:https ://cbonte.github.io/haproxy-dconv/1.9/configuration.html#5.1-crt-list
安全注意事项:始终将您的(敏感)主机名与 SNI 匹配ssl_fc_sni
,而不是 HTTP 主机名。否则,攻击者可能会通过发送 TLS SNIwww.example.org
但将 HTTP 主机名设置为private.example.org
!来绕过您的客户端证书身份验证。
归档时间: |
|
查看次数: |
19333 次 |
最近记录: |