记一次nginx https的坑

image.png

服务器部署了nginx,nginx配置了多个不同域名的server,分别是www.example.comstatic.example.com,还有一个 server_name _ 的默认server。
然后使用curl测试https的时候,发现在访问www.example.com域名时,nginx响应的ssl证书竟然是默认server的,这显然是不正确的,之后经过抓包发现了问题。
原因是nginx默认开启了SNI,如果客户端在ssl握手阶段未携带server_name就会去找默认server,然后使用默认server的ssl证书来响应,nginx没有可以匹配成功的server,只能去找默认server了。下面通过实战还原问题现象。

服务器nginx配置共两个server:默认server(server_name _)和www.example.com

server {
        listen       443 ssl default_server;
        listen       [::]:443 ssl default_server;
        server_name  _;

        ssl_certificate "/etc/nginx/ssl/default_server_rsa.crt";
        ssl_certificate_key "/etc/nginx/ssl/default_server_rsa.key";
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ecdh_curve X25519:P-256;
        ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:HIGH:!NULL:!aNULL:!MD5:!3DES:!DES:!ADH:!RC4:!DH:!DHE:!EXP;

        location / {
        }
}

server {
        listen       443 ssl;
        listen       [::]:443 ssl;
        server_name  example.com www.example.com;

        ssl_certificate "/etc/nginx/ssl/www_server_rsa.crt";
        ssl_certificate_key "/etc/nginx/ssl/www_server_rsa.key";
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
        ssl_ecdh_curve X25519:P-256;
        ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:HIGH:!NULL:!aNULL:!MD5:!3DES:!DES:!ADH:!RC4:!DH:!DHE:!EXP;

        location / {
        }
}

首先看一下两个server的ssl证书内容,可以使用openssl命令查看,留意Subject参数。
default_server_rsa.crt的CN是Default Server,www_server_rsa.crt的CN是example.com

root@k8s-master1:/etc/nginx/ssl# openssl x509 -text -noout -in default_server_rsa.crt 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            5b:75:14:0a:a5:f8:97:da:3b:eb:8d:09:e1:84:e5:67:cb:94:e2:42
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, O = People's Republic of China, CN = Default CA
        Validity
            Not Before: Oct 29 07:22:33 2022 GMT
            Not After : Oct 26 07:22:33 2032 GMT
        Subject: C = CN, O = People's Republic of China, CN = Default Server
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:ee:aa:43:3b:44:08:f5:7e:62:35:f3:35:ac:ba:
                    ...
                    16:41:6e:ba:06:9f:9e:d9:03:d1:27:42:33:28:af:
                    9c:91
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment
    Signature Algorithm: sha256WithRSAEncryption
         27:07:ad:67:18:e2:4d:9c:48:14:c8:eb:f5:6c:2b:a1:7a:95:
         ...
         77:48:03:3c:e6:cc:1d:d2:e5:31:32:bf:4d:6e:a3:df:e3:89:
         d7:e5:4e:cb
root@k8s-master1:/etc/nginx/ssl# 
root@k8s-master1:/etc/nginx/ssl# openssl x509 -text -noout -in www_server_rsa.crt 
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2c:a4:0b:32:9d:ed:2c:e4:98:a3:44:79:dd:c8:8a:a1:5a:16:e0:12
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = CN, O = People's Republic of China, CN = China CA
        Validity
            Not Before: Oct 28 17:12:27 2022 GMT
            Not After : Oct 25 17:12:27 2032 GMT
        Subject: C = CN, O = People's Republic of China, CN = example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:bc:7f:3e:ac:aa:ab:c6:02:74:22:fd:6c:61:43:
                    ...
                    02:38:16:66:69:9c:22:22:ac:96:f3:35:48:61:49:
                    7c:25
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:example.com, DNS:www.example.com
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment
    Signature Algorithm: sha256WithRSAEncryption
         3c:a9:80:3d:b0:7f:f7:c9:e7:eb:1c:06:bb:52:5b:57:cc:15:
         ...
         96:5c:b4:0c:a5:99:30:26:98:6b:ea:16:c2:bb:88:88:a8:20:
         9f:19:a5:d0
root@k8s-master1:/etc/nginx/ssl# 

异常问题可以使用curl复现,发起两个请求,然后看一下有什么区别。

[root@centos ~]# curl -skvo /dev/null https://www.example.com -H "Host: www.example.com" --resolve www.example.com:443:192.168.3.47
* Added www.example.com:443:192.168.3.47 to DNS cache
* About to connect() to www.example.com port 443 (#0)
*   Trying 192.168.3.47...
* Connected to www.example.com (192.168.3.47) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*   subject: CN=example.com,O=People's Republic of China,C=CN
*   start date: Oct 28 17:12:27 2022 GMT
*   expire date: Oct 25 17:12:27 2032 GMT
*   common name: example.com
*   issuer: CN=China CA,O=People's Republic of China,C=CN
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host: www.example.com
> 
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sat, 29 Oct 2022 11:09:33 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 21 Apr 2020 14:09:01 GMT
< Connection: keep-alive
< ETag: "5e9efe7d-264"
< Accept-Ranges: bytes
< 
{ [data not shown]
* Connection #0 to host www.example.com left intact
[root@centos ~]# 
[root@centos ~]# 
[root@centos ~]# curl -skvo /dev/null https://192.168.3.47 -H "Host: www.example.com" --resolve www.example.com:443:192.168.3.47
* Added www.example.com:443:192.168.3.47 to DNS cache
* About to connect() to 192.168.3.47 port 443 (#0)
*   Trying 192.168.3.47...
* Connected to 192.168.3.47 (192.168.3.47) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* skipping SSL peer certificate verification
* SSL connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate:
*   subject: CN=Default Server,O=People's Republic of China,C=CN
*   start date: Oct 29 07:22:33 2022 GMT
*   expire date: Oct 26 07:22:33 2032 GMT
*   common name: Default Server
*   issuer: CN=Default CA,O=People's Republic of China,C=CN
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Accept: */*
> Host: www.example.com
> 
< HTTP/1.1 200 OK
< Server: nginx
< Date: Sat, 29 Oct 2022 11:09:40 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 21 Apr 2020 14:09:01 GMT
< Connection: keep-alive
< ETag: "5e9efe7d-264"
< Accept-Ranges: bytes
< 
{ [data not shown]
* Connection #0 to host 192.168.3.47 left intact
[root@centos ~]# 

第一个请求响应的ssl证书是正确的,第二个请求响应的ssl证书是错的。注意看两个请求ssl握手期间的subject内容,第一个请求中的CN是example.com,这是正确的ssl证书,第二个请求中的CN是Default Server,这个是错的,也说明了访问www.example.com,nginx使用了默认server的ssl证书来响应。
从curl的返回看不出有什么异常,那么就只能通过抓包了。

image.png
image.png

通过抓包分析,发现第一个请求在ssl握手时客户端有携带server_name参数,而第二个请求则是未携带server_name参数,然后nginx就响应默认server的证书。

对于这种情况,客户端在发起请求时必须指定ssl的server_name参数,否则得到的证书就有可能是错误的,例如ssl双向认证也可能有异常。一般支持SNI功能的客户端都是可以配置server_name的。

问题解决之后,不禁感慨。怪不得在调试业务时老是出现问题,通过抓包才发现原来是这东西惹的祸。

另外如果用curl访问https请求,推荐用这条命令。

curl -skvo /dev/null https://www.example.com -H "Host: www.example.com" --resolve www.example.com:443:192.168.3.47
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容