起因 我开发了一个Nginx通用代理服务, 将目标url进行加密生成jwt, 存放于url参数中.
1 2 3 4 target url: https://baidu.com jwt payload: {"target": "https://baidu.com"} jwt: jwt_example url: proxy.example.com?token=jwt_example
当访代理服务时, nginx将获取jwt并解密, 验证token是否过期, 并取出payload中的目标url, 使用proxy_pass进行转发即可. 这种模式非常通用, 适用于资源加速, 隐藏真正的资源地址等用途. 开发完成之后, 运行一直正常, 我一直用来代理某个国外网站的视频资源.
直到最近才发生了错误, 查看nginx日志:
1 SSL_do_handshake() failed (SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number) while SSL handshaking to upstream.
错误 从错误日志可以看出来是SSL握手失败, target url的确是HTTPS的协议, 但是为什么到最近才会出现错误, 之前一直运行正常. 我尝试将target url的协议改成HTTP, 则可以正常代理, 而在访问了HTTP之后再访问HTTPS则正常, 这的确十分诡异. 后来我意识到这其实是因为我开了缓存, 当第一次访问HTTP会将资源缓存下载, 之后代理HTTPS则不会再进行请求, 只是简单的读取缓存.
抓包 当一切都没有头绪的时候, 我开始使用tcpdump进行抓包, 在期间我正常访问并复现错误, 并且使用curl正常访问target url一次. 然后使用wireshark分析pcap文件, wireshark能够清晰有层次的展示出网络报文结构, 包括SSL各个字段意义. 通过观察网络数据, 我发现在发出第一个Client Hello之后, 握手便中断了, 我猜测应该是某个字段遗漏或者填写错误.
所以我提取了nginx/curl两者的Client Hello, 进行详细对比.
nginx client hello:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 Transport Layer Security TLSv1 Record Layer: Handshake Protocol: Client Hello Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 278 Handshake Protocol: Client Hello Handshake Type: Client Hello (1) Length: 274 Version: TLS 1.2 (0x0303) Random: 1f9c1eb1a9e8a36ff7d953967bc0c887bd56b2052552befb… GMT Unix Time: Oct 22, 1986 08:32:49.000000000 CST Random Bytes: a9e8a36ff7d953967bc0c887bd56b2052552befb0400350f… Session ID Length: 32 Session ID: ee143acbaedee8fb98b1dc3d6b90bdedc03cef516d463a55… Cipher Suites Length: 62 Cipher Suites (31 suites) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f) Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9) Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8) Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033) Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d) Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff) Compression Methods Length: 1 Compression Methods (1 method) Compression Method: null (0) Extensions Length: 139 Extension: ec_point_formats (len=4) Type: ec_point_formats (11) Length: 4 EC point formats Length: 3 Elliptic curves point formats (3) Extension: supported_groups (len=12) Type: supported_groups (10) Length: 12 Supported Groups List Length: 10 Supported Groups (5 groups) Extension: session_ticket (len=0) Type: session_ticket (35) Length: 0 Data (0 bytes) Extension: encrypt_then_mac (len=0) Type: encrypt_then_mac (22) Length: 0 Extension: extended_master_secret (len=0) Type: extended_master_secret (23) Length: 0 Extension: signature_algorithms (len=42) Type: signature_algorithms (13) Length: 42 Signature Hash Algorithms Length: 40 Signature Hash Algorithms (20 algorithms) Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403) Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503) Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603) Signature Algorithm: ed25519 (0x0807) Signature Algorithm: ed448 (0x0808) Signature Algorithm: rsa_pss_pss_sha256 (0x0809) Signature Algorithm: rsa_pss_pss_sha384 (0x080a) Signature Algorithm: rsa_pss_pss_sha512 (0x080b) Signature Algorithm: rsa_pss_rsae_sha256 (0x0804) Signature Algorithm: rsa_pss_rsae_sha384 (0x0805) Signature Algorithm: rsa_pss_rsae_sha512 (0x0806) Signature Algorithm: rsa_pkcs1_sha256 (0x0401) Signature Algorithm: rsa_pkcs1_sha384 (0x0501) Signature Algorithm: rsa_pkcs1_sha512 (0x0601) Signature Algorithm: SHA224 ECDSA (0x0303) Signature Algorithm: SHA224 RSA (0x0301) Signature Algorithm: SHA224 DSA (0x0302) Signature Algorithm: SHA256 DSA (0x0402) Signature Algorithm: SHA384 DSA (0x0502) Signature Algorithm: SHA512 DSA (0x0602) Extension: supported_versions (len=5) Type: supported_versions (43) Length: 5 Supported Versions length: 4 Supported Version: TLS 1.3 (0x0304) Supported Version: TLS 1.2 (0x0303) Extension: psk_key_exchange_modes (len=2) Type: psk_key_exchange_modes (45) Length: 2 PSK Key Exchange Modes Length: 1 PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1) Extension: key_share (len=38) Type: key_share (51) Length: 38 Key Share extension Client Key Share Length: 36 Key Share Entry: Group: x25519, Key Exchange length: 32 Group: x25519 (29) Key Exchange Length: 32 Key Exchange: 4f2de7db6676fb0bd1414fe7a39c7b0b9de762faf020f1db…
curl client hello:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 Transport Layer Security TLSv1.2 Record Layer: Handshake Protocol: Client Hello Content Type: Handshake (22) Version: TLS 1.0 (0x0301) Length: 512 Handshake Protocol: Client Hello Handshake Type: Client Hello (1) Length: 508 Version: TLS 1.2 (0x0303) Random: a7b82c9ca56d16f7a2185220dda1738524d36f863807571a… GMT Unix Time: Mar 3, 2059 05:11:56.000000000 CST Random Bytes: a56d16f7a2185220dda1738524d36f863807571a04287add… Session ID Length: 32 Session ID: 49e609bb364d985ddead6c63ef722cc2289f68673155a8a5… Cipher Suites Length: 62 Cipher Suites (31 suites) Cipher Suite: TLS_AES_256_GCM_SHA384 (0x1302) Cipher Suite: TLS_CHACHA20_POLY1305_SHA256 (0x1303) Cipher Suite: TLS_AES_128_GCM_SHA256 (0x1301) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f) Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9) Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8) Cipher Suite: TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xccaa) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014) Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039) Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009) Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013) Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033) Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d) Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c) Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035) Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff) Compression Methods Length: 1 Compression Methods (1 method) Compression Method: null (0) Extensions Length: 373 Extension: server_name (len=21) Type: server_name (0) Length: 21 Server Name Indication extension Extension: ec_point_formats (len=4) Type: ec_point_formats (11) Length: 4 EC point formats Length: 3 Elliptic curves point formats (3) Extension: supported_groups (len=12) Type: supported_groups (10) Length: 12 Supported Groups List Length: 10 Supported Groups (5 groups) Extension: next_protocol_negotiation (len=0) Type: next_protocol_negotiation (13172) Length: 0 Extension: application_layer_protocol_negotiation (len=14) Type: application_layer_protocol_negotiation (16) Length: 14 ALPN Extension Length: 12 ALPN Protocol Extension: encrypt_then_mac (len=0) Type: encrypt_then_mac (22) Length: 0 Extension: extended_master_secret (len=0) Type: extended_master_secret (23) Length: 0 Extension: post_handshake_auth (len=0) Type: post_handshake_auth (49) Length: 0 Extension: signature_algorithms (len=42) Type: signature_algorithms (13) Length: 42 Signature Hash Algorithms Length: 40 Signature Hash Algorithms (20 algorithms) Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403) Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503) Signature Algorithm: ecdsa_secp521r1_sha512 (0x0603) Signature Algorithm: ed25519 (0x0807) Signature Algorithm: ed448 (0x0808) Signature Algorithm: rsa_pss_pss_sha256 (0x0809) Signature Algorithm: rsa_pss_pss_sha384 (0x080a) Signature Algorithm: rsa_pss_pss_sha512 (0x080b) Signature Algorithm: rsa_pss_rsae_sha256 (0x0804) Signature Algorithm: rsa_pss_rsae_sha384 (0x0805) Signature Algorithm: rsa_pss_rsae_sha512 (0x0806) Signature Algorithm: rsa_pkcs1_sha256 (0x0401) Signature Algorithm: rsa_pkcs1_sha384 (0x0501) Signature Algorithm: rsa_pkcs1_sha512 (0x0601) Signature Algorithm: SHA224 ECDSA (0x0303) Signature Algorithm: SHA224 RSA (0x0301) Signature Algorithm: SHA224 DSA (0x0302) Signature Algorithm: SHA256 DSA (0x0402) Signature Algorithm: SHA384 DSA (0x0502) Signature Algorithm: SHA512 DSA (0x0602) Extension: supported_versions (len=5) Type: supported_versions (43) Length: 5 Supported Versions length: 4 Supported Version: TLS 1.3 (0x0304) Supported Version: TLS 1.2 (0x0303) Extension: psk_key_exchange_modes (len=2) Type: psk_key_exchange_modes (45) Length: 2 PSK Key Exchange Modes Length: 1 PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1) Extension: key_share (len=38) Type: key_share (51) Length: 38 Key Share extension Client Key Share Length: 36 Key Share Entry: Group: x25519, Key Exchange length: 32 Group: x25519 (29) Key Exchange Length: 32 Key Exchange: b15a8e88f3f46e4a94dcd6273a89f60aaee9690ed7974975… Extension: padding (len=183) Type: padding (21) Length: 183 Padding Data: 000000000000000000000000000000000000000000000000…
疑惑 令我不解的是, 两个报文的version字段都是一样的(TLS1.2), 但是显示的协议却不一样.
TLSv1 Record Layer: Handshake Protocol: Client Hello TLSv1.2 Record Layer: Handshake Protocol: Client Hello
因为我之前遇到过curl进行SSL握手失败的问题, 错误原因是现在大多数OpenSSL将最低版本设置成TLS1.2. 所以我怀疑是不是TLS版本设置的问题, 但是我尝试了很多种方法, 依旧失败. 随后我更加仔细的对比两个报文, 我发现了一个差异:
Extension: server_name (len=21)
curl的握手报文里面多出一个server_name的字段, 这时我便开始搜索关于SNI的信息. 简单来说如果一个SSL服务上有多个域名服务, 那么客户端在握手报文里面需要附带SNI, 也就是想访问的域名, 这样SSL服务才能为其选择正确的证书.
解决 我搜索了nginx文档后看到:
1 2 3 4 5 6 Syntax: proxy_ssl_server_name on | off; Default: proxy_ssl_server_name off; Context: http, server, location This directive appeared in version 1.7.0. Enables or disables passing of the server name through TLS Server Name Indication extension (SNI, RFC 6066) when establishing a connection with the proxied HTTPS server.
Nginx默认关闭了SNI, 当我打开这个选项之后一切都正常了, 我猜测大概是目标网站最近开启了SNI的选项, 当nginx没有提供SNI的时候就无法正常访问.