HTTPS分析與實戰
名稱解釋 https:一種安全的http協議,因此可以稱為安全的超文本傳輸協議,https提出在http和tcp之間添加一層加密層(SSL層),這一層負責數據的加密和解密。
數字證書:簡稱CA,它由權威機構給某網站頒發的一種認可憑證,是被瀏覽器所認可的,當然證書也可以自己生成,但是這樣就不被瀏覽器所認可,想想如果自己隨便生成一個證書就被瀏覽器認為是安全的,那也挺可怕的;最簡單的證書包含一個公開密鑰、名稱以及證書授權中心的數字簽名,證書都有一個有效期。數字簽名:就是只有信息的發送者才能產生的別人無法偽造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證明。對稱加密:又叫共享密鑰加密,對稱密鑰在加密和解密的過程中使用的密鑰是相同的,常見的對稱加密演算法有DES,AES;優點是計算速度快,缺點是在數據傳送前,發送方和接收方必須商定好秘鑰,然後使雙方都能保存好秘鑰,如果一方的秘鑰被泄露,那麼加密信息也就不安全了。非對稱加密:服務端會生成一對密鑰,私鑰存放在伺服器端,公鑰可以發布給任何人使用;優點就是比起對稱加密更加安全,但是加解密的速度比對稱加密慢太多了。HTTPS握手流程
四次握手過程如下圖所示(圖片來源網上):1.客戶端發送ClientHello
具體數據報文如下:*** ClientHello, TLSv1.2RandomCookie: GMT: 1518006972 bytes = { 65, 176, 64, 48, 101, 197, 66, 45, 233, 201, 4, 212, 39, 207, 197, 221, 77, 28, 131, 219, 59, 92, 71, 77, 188, 128, 9, 85 }Session ID: {}Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]Compression Methods: { 0 }
其中提供的信息包括:TLS的協議版本,客戶端生成的隨機數,支持的加密方法,支持的壓縮方法;
2.伺服器返回SeverHello
*** ServerHello, TLSv1.2RandomCookie: GMT: 1518006972 bytes = { 103, 152, 99, 6, 122, 253, 175, 18, 69, 135, 32, 101, 52, 209, 212, 68, 77, 6, 58, 123, 185, 243, 135, 155, 70, 15, 167, 109 }Session ID: {90, 123, 243, 188, 13, 250, 24, 48, 62, 145, 5, 130, 84, 81, 156, 246, 107, 149, 19, 110, 245, 190, 163, 34, 163, 100, 83, 11, 192, 218, 82, 39}Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHACompression Method: 0
包括:確定使用的TLS協議版本,伺服器生成的隨機數,確認使用的加密方法和壓縮方法;
*** Certificate chainchain [0] = [[ Version: V3 Subject: CN=localhost, OU=codingo, O=codingo, L=nj, ST=js, C=zh Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11 Key: Sun RSA public key, 1024 bits modulus: 110417951066462499519290586842003643785934040448390902213730986659030452849006148579719535028965929817510494601937968191944831386030431983435172428185729866570463573441808893521679337608573348913665909433691909748813081253262417347690775527606654237333218231191786649572821638992076667126149380228808647107891 public exponent: 65537 Validity: [From: Wed Feb 07 11:07:44 CST 2018, To: Sat Feb 05 11:07:44 CST 2028] Issuer: CN=localhost, OU=codingo, O=codingo, L=nj, ST=js, C=zh SerialNumber: [ 5123c55c] .....
主要提供的是伺服器的證書信息,包括伺服器的名稱、受信任的證書頒發機構(CA)和伺服器的公鑰;
*** ECDH ServerKeyExchangeSignature Algorithm SHA512withRSAServer key: Sun EC public key, 256 bits public x coord: 4476231809895366488986368567243788140155223860343081368472893244611384219615 public y coord: 109050381572001188616470974606466310815898076295756191171855198021565796560756 parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)[read] MD5 and SHA1 hashes: len = 205
如果是DH演算法,這裡發送伺服器使用的DH參數,RSA演算法沒有參數;
*** CertificateRequestCert Types: RSA, DSS, ECDSASupported Signature Algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSACert Authorities:<CN=localhost, OU=codingo, O=codingo, L=nj, ST=js, C=zh><CN=localhost, OU=codingo, O=codingo, L=nj, ST=js, C=zh>[read] MD5 and SHA1 hashes: len = 234
伺服器要求客戶端發送客戶端證書,只有在伺服器配置了雙向認證的情況下才需要客戶端證書,我們大部分情況下訪問的網站都不需要客戶端證書,只會在一些對安全性要求很高的場景下才需要,比如銀行領域。
*** ServerHelloDone[read] MD5 and SHA1 hashes: len = 40000: 0E 00 00 00
告訴客戶端ServerHello結束。
3.客戶端返回
*** Certificate chainchain [0] = [[ Version: V3 Subject: CN=localhost, OU=codingo, O=codingo, L=nj, ST=js, C=zh Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11 Key: Sun RSA public key, 1024 bits modulus: 143615763343122571917822119532441620876017906006239941866997048768454765923738744303428875033219696709502897773614201648358563889389642376484119370521476221520354430179070803876160761551600474650108009364863645371886530280727392383823083132045866415069619367905230488064564105401690196419355382565701271042183 public exponent: 65537 Validity: [From: Wed Feb 07 11:08:24 CST 2018, To: Sat Feb 05 11:08:24 CST 2028] Issuer: CN=localhost, OU=codingo, O=codingo, L=nj, ST=js, C=zh SerialNumber: [ 06be5a82]
伺服器配置了雙向認證,所有客戶端需要發送客戶端證書給伺服器,進行認證;
*** ECDHClientKeyExchangeECDH Public value: { 4, 76, 128, 114, 175, 136, 51, 128, 201, 195, 101, 5, 13, 104, 146, 150, 177, 126, 39, 78, 212, 106, 81, 93, 253, 171, 132, 162, 40, 118, 146, 65, 113, 156, 141, 114, 237, 127, 163, 208, 73, 9, 17, 235, 110, 166, 148, 93, 56, 159, 47, 6, 9, 119, 68, 109, 48, 4, 152, 89, 18, 54, 95, 214, 196 }main, WRITE: TLSv1.2 Handshake, length = 684SESSION KEYGEN:PreMaster Secret:......
客戶端收到伺服器的證書,首先會認證證書,認證證書是否是有效的或者可信任的,如果不是瀏覽器會顯示警告頁面;如果沒有問題客戶端會從伺服器端的證書中獲取公鑰,再生成一個隨機數,再用公鑰對這個隨機數加密生成PreMaster Secret,發送給伺服器;這樣伺服器和客戶端都有了三個隨機數,在通過相同的演算法生成一個應用層通訊的對稱密鑰;
main, WRITE: TLSv1.2 Change Cipher Spec, length = 1[Raw write]: length = 60000: 14 03 03 00 01 01 ......*** Finishedverify_data: { 181, 183, 221, 94, 78, 87, 6, 226, 234, 202, 181, 9 }
Change Cipher Spec消息客戶端通知服務端後面再發送的消息都會使用前面協商出來的秘鑰加密了;
Finished消息客戶端將前面的握手消息加密發出了第一條加密數據,伺服器如果可以解密說明密鑰是一致的;4.伺服器返回
main, READ: TLSv1.2 Change Cipher Spec, length = 1[Raw read]: length = 50000: 16 03 03 00 40 *** Finishedverify_data: { 54, 167, 25, 231, 214, 98, 110, 203, 169, 108, 148, 225 }***
Change Cipher Spec消息服務端通知客戶端後面再發送的消息都會使用前面協商出來的秘鑰加密了;
Finished消息服務端將前面的握手消息加密發出了第一條加密數據發送給客戶端;整個握手流程大致如此,接下來就是通過對稱加密來傳輸業務數據了。
雙向認證實現
正規的網站一般數字證書都是由權威機構發布的證書,操作系統和瀏覽器都認可,但是價格比較昂貴(當然也有免費的比如:Let』s Encrypt);當然也可以使用自簽名證書,下面使用JDK自帶工具KeyTool來生成自簽名證書,並且在tomcat中使用;1.生成伺服器端證書
使用keyTool命令生成伺服器端證書:C:Program FilesJavajdk1.7.0_80in>keytool -genkey -alias tomcat -keypass 111111 -keyalg RSA -keysize 1024 -validity 3650 -keystore E: omcat.keystore -storepass 111111
參數說明:-alias:別名,-keypass:別名密碼,-keyalg:指定的加密演算法,-validity:有效期,-keystore:keystore存儲的目錄,-storepass:獲取keystroe的密碼
因為在本地測試,所以」您的名字與姓氏是什麼?」 填localhost,一步步添加數據完之後生成了tomcat.keystore文件;2.生成客戶端證書
使用keyTool命令生成客戶端證書:C:Program FilesJavajdk1.7.0_80in>keytool -genkey -alias client -keypass 111111 -keyalg RSA -keysize 1024 -validity 3650 -storetype PKCS12 -keystore E:client.p12 -storepass 111111
為了能夠導入到瀏覽器中,證書格式應該是PKCS12,一步步添加數據完之後生成了client.p12文件;
3.讓伺服器信任客戶端證書
讓伺服器信任客戶端證書,需要將客戶端證書導入到伺服器證書中,添加為一個信任證書,但是首先需要把PKCS12格式轉為cer文件:C:Program FilesJavajdk1.7.0_80in>keytool -export -alias client -keystore E:client.p12 -storetype PKCS12 -keypass 111111 -file E:client.cerC:Program FilesJavajdk1.7.0_80in>keytool -import -v -file E:client.cer -keystore E: omcat.keystore -storepass 111111C:Program FilesJavajdk1.7.0_80in>keytool -list -v -keystore E: omcat.keystore
最後的list命令,查看一下當前您的密鑰庫是否包含2個條目;
4.讓客戶端信任伺服器
需要將伺服器證書導入到瀏覽器的」受信任的根證書頒發機構」,導入之前先將tomcat.keystore轉為server.cer,方便瀏覽器導入;C:Program FilesJavajdk1.7.0_80in>keytool -keystore E: omcat.keystore -export -alias tomcat -file E:server.cer
瀏覽器導入:設置->管理證書->受信任的根證書頒發機構->導入server.cer;
因為是雙向認證,所有同樣需要在」個人」一欄中添加client.p12:設置->管理證書->個人->導入client.p12;5.配置tomcat
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true" maxThreads="150" scheme="https" chemeecure="true" clientAuth="true" sslProtocol="TLS" keystoreFile="E:\tomcat.keystore" keystorePass="111111" truststoreFile="E:\tomcat.keystore" truststorePass="111111"/>
keystoreFile:伺服器證書文件路徑,keystorePass:伺服器證書密碼,truststoreFile:用來驗證客戶端證書的根證書,truststorePass:根證書密碼,clientAuth:是否雙向驗證
6.瀏覽器訪問
在chrome中輸入:https://localhost:8443,顯示如下圖所示:
雖然已經設置了伺服器端證書為受信任的,但是不是權威機構認證的,瀏覽器還是顯示為不安全的連接;
7.HttpClient4訪問
使用HttpClient4同樣需要認證伺服器端證書,並且需要發送客戶端證書進行雙向認證,具體代碼如下:public class HttpClient4 { public static void main(String[] args) throws Exception { System.setProperty("javax.net.debug", "all"); KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream(new File("E:\client.p12")), "111111".toCharArray()); SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() { public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }).loadKeyMaterial(keyStore, "111111".toCharArray()).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1.2" }, null, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); HttpGet get = new HttpGet(); get.setURI(new URI("https://localhost:8443/")); httpClient.execute(get); }}
如果不傳客戶端證書進行雙向認證,回出現如下錯誤:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
總結
本文主要對https的握手過程介紹了一下,同時以自簽名的方式在tomcat上進行實際演示;由Let』s Encrypt機構生成的證書可以在瀏覽器上看到「安全」的標識,個人網站就使用了Let』s Encrypt的免費方式,具體可以看參考。參考:
https://coolshell.cn/articles/18094.htmlhttps://zh.wikipedia.org/wiki/%E5%82%B3%E8%BC%B8%E5%B1%A4%E5%AE%89%E5%85%A8%E6%80%A7%E5%8D%94%E5%AE%9A
https://www.bf361.com/system/centos-apache-LetsEncrypt
推薦閱讀:
※iOS 客戶端 HTTPS 防中間人攻擊實踐
※【對標TensorFlow】阿里公開內部超大規模分散式機器學習平台
※大致介紹下SSL?
※HTTPS 可能被這樣劫持嗎?
※為什麼 2015 年底各大網站都紛紛用起了 HTTPS?
TAG:HTTPS |