1. 问题描述
在一台Server上部署有一个https的service(这个service用于为Android Client提供服务),之前一直正常,从某一天开始突然不能正常访问,有的机型一直在nginx中报 400 bad request, 有的则正常访问.
两个问题:
Question 1: 为什么一部分机型突然不正常了?
Question 2: 为什么是一部分机型正常,一部分机型不正常?
2. 环境描述
本台Server上部署了两套完全不相关的Service,都是使用https, 两套的证书完全不一样,并且不是同一个CA签发的,
上述出错的service是a.com下的service
server {
listen 443
server_name a.com
ssl on
ssl_certificate a.com.crt;
ssl_certificate_key a.com.key;
...
}
server {
listen 443
server_name b.cn
ssl on
ssl_certificate b.cn.crt;
ssl_certificate_key b.cn.key;
...
}
3. Q1分析
nginx的access log打出来 400, 可能是建立连接https连接的时候出错了,没有更详细的信息了,所以有以下分析
1. Server上使用tcpdump抓包, wireshark分析结果
tcpdump -w debug.pcap
过程10,Server下发了证书
过程15,Client报错, Alert(Level Fatal, Description: Certificate Unknown)
- 查看过程10中下发证书的详情
发现请求a.com过程中下发的证书竟然是b.cn的,难以置信,但是至少发现了不可理解的地方,然后google找到nginxg文档中有这样的解释:
Name-based HTTPS servers
A common issue arises when configuring two or more HTTPS servers listening on a single IP address:
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
...
}
server {
listen 443 ssl;
server_name www.example.org;
ssl_certificate www.example.org.crt;
...
}
With this configuration a browser receives the default server’s certificate, i.e. www.example.com regardless of the requested server name. This is caused by SSL protocol behaviour. The SSL connection is established before the browser sends an HTTP request and nginx does not know the name of the requested server. Therefore, it may only offer the default server’s certificate.