Bash

使用 openssl s_client 測試 HTTP/2

  • February 10, 2016

CloudFlare關於調試、測試和使用 HTTP/2 的工具的部落格文章提到了這種找出給定伺服器支持哪些協議的方法:

$ openssl s_client -connect www.cloudflare.com:443 -nextprotoneg ''
CONNECTED(00000003)
Protocols advertised by server: h2, spdy/3.1, http/1.1

這種方法似乎適用於我測試過的許多領域。但是,(啟用 HTTP/2 的)域benchmarkjs.com產生的輸出看起來完全不同,我不知道為什麼:

$ openssl s_client -connect benchmarkjs.com:443 -nextprotoneg ''
CONNECTED(00000003)
depth=0 C = US, ST = Washington, L = Seattle, O = Odin, OU = Plesk, CN = Plesk, emailAddress = info@plesk.com
verify error:num=18:self signed certificate
verify return:1
depth=0 C = US, ST = Washington, L = Seattle, O = Odin, OU = Plesk, CN = Plesk, emailAddress = info@plesk.com
verify return:1
---
Certificate chain
0 s:/C=US/ST=Washington/L=Seattle/O=Odin/OU=Plesk/CN=Plesk/emailAddress=info@plesk.com
  i:/C=US/ST=Washington/L=Seattle/O=Odin/OU=Plesk/CN=Plesk/emailAddress=info@plesk.com
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDfTCCAmUCBFXIlUswDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNVBAYTAlVTMRMw
EQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMQ0wCwYDVQQKDARP
ZGluMQ4wDAYDVQQLDAVQbGVzazEOMAwGA1UEAwwFUGxlc2sxHTAbBgkqhkiG9w0B
CQEWDmluZm9AcGxlc2suY29tMB4XDTE1MDgxMDEyMTMwMFoXDTE2MDgwOTEyMTMw
MFowgYIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH
DAdTZWF0dGxlMQ0wCwYDVQQKDARPZGluMQ4wDAYDVQQLDAVQbGVzazEOMAwGA1UE
AwwFUGxlc2sxHTAbBgkqhkiG9w0BCQEWDmluZm9AcGxlc2suY29tMIIBIjANBgkq
hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvLgc48tQHJaVZj4btZhGySqNlQeXRti8
Nansm15wJXS45EIFx6lYqFbDjD22VBwwDrILNZBY9BiKLV+VsZYuu1sOK+Ctatww
gcOf4UB5pT6kOP48vBJlsaxqf+kCQpiVBniliLs7yAxl3BjjzQBluI4DUMXGpsuD
u2tBi/fsUV6QRBzsebQ6cH5cZ9XPGiirPyFe7yNNbXurooYmeD1YjEH6qYIPhU9O
lTOU9rssii8ShmHL/X54ekIqZ9y5b3eD+Dhp45/WjxXcgSxWZHx8SYcKndiSOJFa
KUXlBKREmvH1nQLtp1BdCH6BiLPXaMMcRPY1BUhLSLt6M68B5vRDqQIDAQABMA0G
CSqGSIb3DQEBCwUAA4IBAQAvTuPoc0RYHXeHW61s6PPC7pRtp1t+roknJPa/po1P
vFtINtR9vuCfeUfS7K8ryfduBkX/km8qjCxjNvjQsJdya5mfMdPzW4AabJs06qUp
h5PPk2ER1OcPzraemcHHL8gzStVk3n9C23ZRAwZaEIsgnOQ58YGf4eyrzKXBClfL
NPL28cQQH5+d4lIsQc7B9d0OiiUQNTBfVD/CA67SPvc/f6Xq7ARdrc44GhA03cUN
0Vr60j2kv9IkdSnRPtt40R8AD97bKu9E/jOJCrSOfCbB3Qz1Pdm2lZqSEnoHdlbg
2KY8HrvoEXvuPUNXRIQEhpR7f9y70iBPORs0PbuC+qDf
-----END CERTIFICATE-----
subject=/C=US/ST=Washington/L=Seattle/O=Odin/OU=Plesk/CN=Plesk/emailAddress=info@plesk.com
issuer=/C=US/ST=Washington/L=Seattle/O=Odin/OU=Plesk/CN=Plesk/emailAddress=info@plesk.com
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: ECDH, P-256, 256 bits
---
SSL handshake has read 1409 bytes and written 448 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
   Protocol  : TLSv1.2
   Cipher    : ECDHE-RSA-AES128-GCM-SHA256
   Session-ID: C0474D42297C21B374C558E698A69EEBBFF537B35E6365D31B4D7AA2CD4192AD
   Session-ID-ctx:
   Master-Key: 2292DF581DAE3CE4A4E8CFF5A351A3F4E99602A7DCDBD090998C38926498743B4E3A808A1C4505136D51FC847F0153A6
   Key-Arg   : None
   PSK identity: None
   PSK identity hint: None
   SRP username: None
   Start Time: 1455103745
   Timeout   : 300 (sec)
   Verify return code: 18 (self signed certificate)
---

請注意,它不會返回提示;您已連接到伺服器,現在可以輸入 egGET / HTTP/1.1後跟Host: benchmarkjs.com.

所以,我的兩個問題是:

  1. 這有什麼不同benchmarkjs.com使這種技術不起作用?
  2. 是否有可能以openssl s_client一種通用的方式檢測 HTTP/2 支持,即使該域也適用?

我的看法:openssl s_client的手冊指出:

-nextprotoneg 協議

啟用 Next Protocol Negotiation TLS擴展並提供一個逗號分隔的協議名稱列表,客戶端應該宣傳支持的協議名稱。該列表應首先包含最想要的協議。協議名稱是可列印的 ASCII 字元串,例如“http/1.1”或“spdy/3”。空的協議列表被特殊處理,將導致客戶端宣傳對 TLS 擴展的支持,但在收到帶有伺服器支持協議列表的 ServerHello 後立即斷開連接。

(強調我的。)

因此,我會說終止您的請求的 SSL/TLS 引擎benchmarkjs.com僅不支持 Next Protocol Negotiation 擴展或由於某種原因將其禁用。因此,在您的測試中,該openssl s_client命令宣傳支持 NPN,但伺服器對 ot 視而不見。握手仍然可以通過,因為擴展似乎不是必需的(或至少被認為是不必要的openssl)並且您獲得了連接的 TLS 隧道。

至於實現可靠檢查,恐怕因為openssl s_client顯然沒有任何命令行選項會強制它立即終止會話,所以您必須更深入並編寫自己的程序連結到libssl該程序將實現所需的行為. (我個人會在Go中使用crypto/tls其標準庫的包來實現它,因為它的程式並不比 JavaScript 難,但會生成一個靜態連結的程序,這意味著無需大腦部署。)

引用自:https://serverfault.com/questions/755236