https:一種安全的http協議,所以能夠稱爲安全的超文本傳輸協議,https提出在http和tcp之間添加一層加密層(SSL層),這一層負責數據的加密和解密。
數字證書:簡稱CA,它由權威機構給某網站頒發的一種承認憑證,是被瀏覽器所承認的,固然證書也能夠本身生成,可是這樣就不被瀏覽器所承認,想一想若是本身隨便生成一個證書就被瀏覽器認爲是安全的,那也挺可怕的;最簡單的證書包含一個公開密鑰、名稱以及證書受權中心的數字簽名,證書都有一個有效期。
數字簽名:就是隻有信息的發送者才能產生的別人沒法僞造的一段數字串,這段數字串同時也是對信息的發送者發送信息真實性的一個有效證實。
對稱加密:又叫共享密鑰加密,對稱密鑰在加密和解密的過程當中使用的密鑰是相同的,常見的對稱加密算法有DES,AES;優勢是計算速度快,缺點是在數據傳送前,發送方和接收方必須商定好祕鑰,而後使雙方都能保存好祕鑰,若是一方的祕鑰被泄露,那麼加密信息也就不安全了。
非對稱加密:服務端會生成一對密鑰,私鑰存放在服務器端,公鑰能夠發佈給任何人使用;優勢就是比起對稱加密更加安全,可是加解密的速度比對稱加密慢太多了。html
四次握手過程以下圖所示(圖片來源網上):java
具體數據報文以下:算法
*** ClientHello, TLSv1.2 RandomCookie: 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的協議版本,客戶端生成的隨機數,支持的加密方法,支持的壓縮方法;chrome
*** ServerHello, TLSv1.2 RandomCookie: 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_SHA Compression Method: 0
包括:肯定使用的TLS協議版本,服務器生成的隨機數,確認使用的加密方法和壓縮方法;shell
*** Certificate chain chain [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)和服務器的公鑰;apache
*** ECDH ServerKeyExchange Signature Algorithm SHA512withRSA Server 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算法沒有參數;centos
*** CertificateRequest Cert Types: RSA, DSS, ECDSA Supported Signature Algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA, MD5withRSA Cert 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 = 4 0000: 0E 00 00 00
告訴客戶端ServerHello結束。tomcat
*** Certificate chain chain [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]
服務器配置了雙向認證,全部客戶端須要發送客戶端證書給服務器,進行認證;安全
*** ECDHClientKeyExchange ECDH 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 = 684 SESSION KEYGEN: PreMaster Secret: ......
客戶端收到服務器的證書,首先會認證證書,認證證書是不是有效的或者可信任的,若是不是瀏覽器會顯示警告頁面;若是沒有問題客戶端會從服務器端的證書中獲取公鑰,再生成一個隨機數,再用公鑰對這個隨機數加密生成PreMaster Secret,發送給服務器;這樣服務器和客戶端都有了三個隨機數,在經過相同的算法生成一個應用層通信的對稱密鑰;
main, WRITE: TLSv1.2 Change Cipher Spec, length = 1 [Raw write]: length = 6 0000: 14 03 03 00 01 01 ...... *** Finished verify_data: { 181, 183, 221, 94, 78, 87, 6, 226, 234, 202, 181, 9 }
Change Cipher Spec消息客戶端通知服務端後面再發送的消息都會使用前面協商出來的祕鑰加密了;
Finished消息客戶端將前面的握手消息加密發出了第一條加密數據,服務器若是能夠解密說明密鑰是一致的;
main, READ: TLSv1.2 Change Cipher Spec, length = 1 [Raw read]: length = 5 0000: 16 03 03 00 40 *** Finished verify_data: { 54, 167, 25, 231, 214, 98, 110, 203, 169, 108, 148, 225 } ***
Change Cipher Spec消息服務端通知客戶端後面再發送的消息都會使用前面協商出來的祕鑰加密了;
Finished消息服務端將前面的握手消息加密發出了第一條加密數據發送給客戶端;
整個握手流程大體如此,接下來就是經過對稱加密來傳輸業務數據了。
正規的網站通常數字證書都是由權威機構發佈的證書,操做系統和瀏覽器都承認,可是價格比較昂貴(固然也有免費的好比:Let’s Encrypt);固然也可使用自簽名證書,下面使用JDK自帶工具KeyTool來生成自簽名證書,而且在tomcat中使用;
使用keyTool命令生成服務器端證書:
C:\Program Files\Java\jdk1.7.0_80\bin>keytool -genkey -alias tomcat -keypass 111111 -keyalg RSA -keysize 1024 -validity 3650 -keystore E:\tomcat.keystore -storepass 111111
參數說明:-alias:別名,-keypass:別名密碼,-keyalg:指定的加密算法,-validity:有效期,-keystore:keystore存儲的目錄,-storepass:獲取keystroe的密碼
由於在本地測試,因此」您的名字與姓氏是什麼?」 填localhost,一步步添加數據完以後生成了tomcat.keystore文件;
使用keyTool命令生成客戶端證書:
C:\Program Files\Java\jdk1.7.0_80\bin>keytool -genkey -alias client -keypass 111111 -keyalg RSA -keysize 1024 -validity 3650 -storetype PKCS12 -keystore E:\client.p12 -storepass 111111
爲了可以導入到瀏覽器中,證書格式應該是PKCS12,一步步添加數據完以後生成了client.p12文件;
讓服務器信任客戶端證書,須要將客戶端證書導入到服務器證書中,添加爲一個信任證書,可是首先須要把PKCS12格式轉爲cer文件:
C:\Program Files\Java\jdk1.7.0_80\bin>keytool -export -alias client -keystore E:\client.p12 -storetype PKCS12 -keypass 111111 -file E:\client.cer C:\Program Files\Java\jdk1.7.0_80\bin>keytool -import -v -file E:\client.cer -keystore E:\tomcat.keystore -storepass 111111 C:\Program Files\Java\jdk1.7.0_80\bin>keytool -list -v -keystore E:\tomcat.keystore
最後的list命令,查看一下當前您的密鑰庫是否包含2個條目;
須要將服務器證書導入到瀏覽器的」受信任的根證書頒發機構」,導入以前先將tomcat.keystore轉爲server.cer,方便瀏覽器導入;
C:\Program Files\Java\jdk1.7.0_80\bin>keytool -keystore E:\tomcat.keystore -export -alias tomcat -file E:\server.cer
瀏覽器導入:設置->管理證書->受信任的根證書頒發機構->導入server.cer;
由於是雙向認證,全部一樣須要在」我的」一欄中添加client.p12:設置->管理證書->我的->導入client.p12;
<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:是否雙向驗證
在chrome中輸入:https://localhost:8443,顯示以下圖所示:
雖然已經設置了服務器端證書爲受信任的,可是不是權威機構認證的,瀏覽器仍是顯示爲不安全的鏈接;
使用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...
https://zh.wikipedia.org/wiki...
https://www.bf361.com/system/...