HTTPS和HTTPS证书
背景:我發現網上真的沒有幾個把https講清楚的,更別說證書,以及證書安裝,更是一堆沒用的軟文,所以在看了很多資料后做下記錄
HTTPS協議
超文本傳輸安全協議(英語:Hypertext Transfer Protocol Secure,縮寫:HTTPS,常稱為HTTP over TLS,HTTP over SSL或HTTP Secure)是一種網絡安全傳輸協議。具體介紹以前先來介紹一下以前常見的HTTP,HTTP就是我們平時瀏覽網頁時候使用的一種協議。HTTP協議傳輸的數據都是未加密的,也就是明文,因此使用HTTP協議傳輸隱私信息非常不安全。HTTP使用80端口通訊,而HTTPS占用443端口通訊。在計算機網絡上,HTTPS經由超文本傳輸協議(HTTP)進行通信,但利用SSL/TLS來加密數據包。HTTPS開發的主要目的,是提供對網絡服務器的身份認證,保護交換數據的隱私與完整性。這個協議由網景公司(Netscape)在1994年首次提出,隨后擴展到互聯網上。
其主要特性(主要是因為):
- https協議需要到ca申請證書,一般免費證書很少,需要交費。 (這里主要是利用了非對稱加密的公鑰加密來解決密鑰傳輸問題)
- http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。?
- http和https使用的是完全不同的連接方式用的端口也不一樣,前者是80,后者是443。?
- http的連接很簡單,是無狀態的 。?
- HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議, 要比http協議安全。
?HTTPS對應的通信時序圖如下:
?
SSL 證書
從前面我們可以了解到HTTPS核心的一個部分是數據傳輸之前的握手,握手過程中確定了數據加密的密碼。在握手過程中,網站會向瀏覽器發送SSL證書,SSL證書和我們日常用的身份證類似,是一個支持HTTPS網站的身份證明,SSL證書里面包含了網站的域名,證書有效期,證書的頒發機構以及用于加密傳輸密碼的公私鑰等信息,由于公鑰加密的密碼只能被在申請證書時生成的私鑰解密,因此瀏覽器在生成密碼之前需要先核對當前訪問的域名與證書上綁定的域名是否一致,同時還要對證書的頒發機構進行驗證,如果驗證失敗瀏覽器會給出證書錯誤的提示。在這一部分我將對SSL證書的驗證過程以及個人用戶在訪問HTTPS網站時,對SSL證書的使用需要注意哪些安全方面的問題進行描述。服務端和客戶端對證書的處理是不一樣的,但是都需要證書。
握手過程的具體描述如下:
- 1)瀏覽器將自己支持的一套加密規則發送給網站。?
- 2)網站從中選出一組加密算法與HASH算法,并將自己的身份信息以證書的形式發回給瀏覽器。證書里面包含了網站地址,加密公鑰,以及證書的頒發機構等信息。??
- 3)瀏覽器獲得網站證書之后瀏覽器要做以下工作:??a)?驗證證書的合法性(頒發證書的機構是否合法,證書中包含的網站地址是否與正在訪問的地址一致等),如果證書受信任,則瀏覽器欄里面會顯示一個小鎖頭,否則會給出證書不受信的提示。??b) 如果證書受信任,或者是用戶接受了不受信的證書,瀏覽器會生成一串隨機數的密碼,并用證書中提供的公鑰加密。??c)?使用約定好的HASH算法計算握手消息,并使用生成的隨機數對消息進行加密,最后將之前生成的所有信息發送給網站。?
這里瀏覽器與網站互相發送加密的握手消息并驗證,目的是為了保證雙方都獲得了一致的密碼,并且可以正常的加密解密數據,為后續真正數據的傳輸做一次測試。(主要是保證加密真正加密信息的密鑰的安全性)
?
這里為很疑惑服務器的私鑰要怎么獲得? 一般兩種,如果是自己去帶著公鑰去申請證書,首先要自己生成密鑰對,然后去請求,所以自己知道自己的私鑰。還有一種是公司其它部門負責申請證書。那這個時候會以pfx的格式給你,里面就包含了你的私鑰。
證書格式和轉換
什么是證書?為什么要使用證書?
對數據進行簽名(加密)是我們在網絡中最常見的安全操作。簽名有雙重作用,作用一就是保證數據的完整性,證明數據并非偽造,而且在傳輸的過程中沒有被篡改,作用二就是防止數據的發布者否認其發布了該數據。
簽名同時使用了非對稱性加密算法和消息摘要算法,對一塊數據簽名時,會先對這塊數據進行消息摘要運算生成一個摘要,然后對該摘要使用發布者的私鑰進行加密。 比如微信公眾平臺開發中最常見的調用api接口方法是將參數進行字典序排序,然后將參數名和參數值接成一個字符串,組合的字符串也就相當于我們這里說的摘要,然后將摘要用平臺密鑰加密。
接收者(客戶端)接受到數據后,先使用發布者的公鑰進行解密得到原數據的摘要,再對接收到的數據計算摘要,如果兩個摘要相同,則說明數據沒有被篡改。同時,因為發布者的私鑰是不公開的,只要接收者通過發布者的公鑰能成功對數據進行解密,就說明該數據一定來源于該發布者。
那么怎么確定某公鑰一定是屬于某發布者的呢?這就需要證書了。證書由權威認證機構頒發,其內容包含證書所有者的標識和它的公鑰,并由權威認證機構使用它的私鑰進行簽名。信息的發布者通過在網絡上發布證書來公開它的公鑰,該證書由權威認證機構進行簽名,認證機構也是通過發布它的證書來公開該機構的公鑰,認證機構的證書由更權威的認證機構進行簽名,這樣就形成了證書鏈。證書鏈最頂端的證書稱為根證書,根證書就只有自簽名了。總之,要對網絡上傳播的內容進行簽名和認證,就一定會用到證書。關于證書遵循的標準,最流行的是 X.509
主流的Web服務軟件,通常都基于兩種基礎密碼庫:OpenSSL和Java。(一般在公司中我們不必自己生成證書文件,獲取jks或者crt格式的證書。然后通過openssl和keytool工具轉換成我們需要的格式即可)
證書的格式主要分成兩類,其一為密鑰庫文件格式、其二為證書文件格式;(分類主要是依據加密方式和包含內容來區分的)
密鑰庫文件格式【Keystore】:java證書內容存在Keystore中,Keystore中可以是jks或者pk12
證書文件格式【Certificate】:
各種平臺,各種語言,它們采用的證書格式與標準都不相同,多多少少存在一些差異。實際上證書仍然是那個證書,只是格式發生了變化。
公私鑰合并為一個文件
有些采用二進制文件
有些事二進制文件做了BASE64編碼
有些證書做了簽名
有些證書加入了密碼
不同組織有不同的編碼。例如微軟喜歡使用 x509
一般服務端證書會以.pfx的形式下發,如下
pfx是一種文件存儲格式, pkcs12是它的實現, 通常里面同時包含私鑰, 公鑰, 證書, 方便存儲和傳播。
證書certificate中包括含了數字簽名和公鑰, 客戶端可以通過CA來驗證數字簽名.
公鑰/私鑰用于數據加密, 公鑰可以發布給任何人, 私鑰必須保密,所以pfx不要隨便傳播
證書文件通常以.cer, .crt結尾? ---BEGIN CERTIFICATE-
公鑰文件通常以.pem結尾? ? ---BEGIN CERTIFICATE-
私鑰文件通常以.key結尾? ? BEGIN PRIVATE?KEY? ??
注意:通常是大家一般這么干,但是不代表這些文件里面不能裝私鑰或者證書。
加密系統加載這些文件時, 并不是以后綴名的區分. 而是根據里面的內容一般公司申請證書如果不是自己生成,都是由的部門生成好后給你的一般是pfx格式:
我們來看一個例子:
一、生成key
openssl genrsa -out openssl.key 1024
openssl.key??是生產key的名稱可隨意 。 1024是生成密鑰的長度。
二、生成cer證書
openssl req -new -x509 -key openssl.key -out openssl.cer -days 3650 -subj /CN=baidu.com
penssl.key為之前生成的key的名字,openssl.cer為生成的證書名字,3650為證書過期天數,CN的參數baidu.com是的你主機名或者IP地址。
三、生成pfx證書
??注意:生成pfx證書會提示設置密碼,此密碼要記住,提取密鑰時要輸入此密碼。
openssl pkcs12 -export -out openssl.pfx -inkey openssl.key -in openssl.cer
一般我們在別的機構申請的證書pfx,就已經完成了前三步。我們直接拿到的是帶有密鑰對和ca機構用私鑰簽名的pfx格式的證書
四、從pfx里提取出私鑰
openssl pkcs12 -in openssl.pfx -nocerts -nodes -out pri.key?
?五:從pfx中提取出公鑰或者證書(如果是客戶端證書公鑰等價于客戶端證書,因為證書就是由ca簽名的公鑰)
openssl pkcs12 -in openssl.pfx -clcerts -nokeys -nodes -out pub.key。or
openssl pkcs12 -in openssl.pfx -clcerts -nokeys -nodes -out cl.certpkcs12——用來處理pkcs#12格式的證書
-export——執行的是導出操作
-clcerts——導出的是客戶端證書,-cacerts則表示導出的是ca證書.?
-inkey——證書的私鑰路徑
-onkeys——不包含私鑰
-in——要導出的證書的路徑
-out——輸出的密鑰庫文件的路徑
六:轉換為java需要使用的格式:
如果你是作為服務端(同時需要自己的公鑰和私鑰):
keytool -importkeystore -srckeystore openssl.pfx -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype JKS
如果想把證書給客戶端而不想暴露自己的私鑰:
1、第五步之后
keytool -importkeystore -srckeystore cl.cert -srcstoretype pkcs12 -destkeystore truststore.jks -deststoretype JKS(使用ca證書和客戶端證書可以保證證書的拆封)
關于證書和證書鏈的拆封原理:理解證書和證書鏈_求變,從思想開始-CSDN博客_證書鏈。簡單來說我用root的那個ca機構的公鑰通過證書鏈可以解開我任意子證書的簽名。
證書的更多知識:
openssl介紹:openssl_百度百科
keytool介紹:keytool_百度百科
常用密鑰格式轉換:靈活多變的keytool和openssl生成證書,應用tomcat和nginx_陳袁的博客-CSDN博客_keytool nginx
證書中常用名詞解釋:OpenSSL中證書格式的區別以及格式的轉換_Ztw的博客-CSDN博客_openssl證書類型
證書生成和查看:用openssl 和 keytool 生成 SSL證書 - 簡書
使用openssl生成證書:使用OpenSSL生成證書_yine的專欄-CSDN博客
openssl證書轉換:?使用openssl生成證書、cer文件、key公私鑰、pem公私鑰_Solyutian的博客-CSDN博客_生成cer文件
java使用證書和安裝證書
Java 使用了一種叫?keystore(后綴一般 是.jks或者.keystore或.truststore等,千奇百怪。不管什么后綴,它就是一個容器,各個公司或機構叫法不同而已。比如把只包含”受 信任的公鑰”的容器成.truststore文件等)?的文件來存儲證書 (默認是位于?$JAVA_HOME/lib/security/cacerts?) 。
該文件使用?keytool?工具去管理 (該工具默認位于?$JAVA_HOME/bin/keytool?)。
首先需要理解什么是keystore:
keystore可以看成一個放key的庫,key就是公鑰,私鑰,數字簽名等組成的一個信息。
truststore是放信任的證書的一個store?
truststore和keystore的性質是一樣的,都是存放key的一個倉庫,區別在于,truststore里存放的是只包含公鑰的數字證書,代表了可以信任的證書,而keystore是包含私鑰的。?
keytool 工具的使用不在這里展開,網上有比較詳細的說明。這里主要列舉幾個會用到的命令。
1). 列出 keystore 中的證書。
keytool -list默認情況下,它會在你的 $HOME 目錄下產生一個空的 .keystore 文件。如要指定 Java 正在用的 keystore 文件,使用以下參數
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts keytool -list -keystore "%JAVA_HOME%/jre/lib/security/cacerts"注意一下, keystore 文件都受 密碼 保護。生成新的 keystore 文件時,會要求你輸入一個新密碼;而當訪問一個已有的 keystore 文件時,會要求你驗證密碼。
$JAVA_HOME/lib/security/cacerts 的默認密碼為 “changeit” !!!
$JAVA_HOME/lib/security/cacerts 的默認密碼為 “changeit” !!!
$JAVA_HOME/lib/security/cacerts 的默認密碼為 “changeit” !!!
重要的事情說三遍!!!
keytool -importkeystore -srckeystore openssl.pfx -srcstoretype pkcs12 -destkeystore keystore.jks -deststoretype JKS
如果不指定 -destkeystore選項,則缺省密鑰倉庫將是宿主目錄中名為 .keystore 的文件。如果該文件并不存在,則它將被創建。
創建密鑰倉庫時會要求輸入訪問口令,以后需要使用此口令來訪問。可使用-list命令來查看密鑰倉庫里的內容:
? ? ? keytool -list -rfc -keystore keystore.jks
然后你需要把這個jks放到$JAVA_HOME/lib/security/cacerts這個文件夾下面,java通過兩個系統屬性來指向這個文件夾:
javax.net.ssl.keyStore和javax.net.ssl.trustStore
javax.net.ssl.keyStore和javax.net.ssl.trustStore用于指定要用于兩個不同目的密鑰存儲庫。
這個javax.net.ssl.keyStore和javax.net.ssl.trustStore參數是用于生成KeyManagerS和TrustManagerS(分別),然后用于構建SSLContext控件進行SSL/TLS連接時使用的SSL/TLS設置。SSLSocketFactory或者SSLEngine..這些系統屬性正是默認值的來源,然后由SSLContext.getDefault(),它本身被SSLSocketFactory.getDefault()例如。(所有這些都可以通過API在許多地方進行自定義,如果您不想使用默認值和特定的SSLContextIt‘為某一特定目的而設。)
之間的差異KeyManager和TrustManager(因此在javax.net.ssl.keyStore和javax.net.ssl.trustStore)如下(引用自JSSE參考指南):
TrustManager:確定是否應該信任遠程身份驗證憑據(以及連接)。
KeyManager:確定要發送到遠程主機的身份驗證憑據(其他參數可用,其默認值在JSSE參考指南..請注意,雖然信任存儲有默認值,但密鑰存儲沒有默認值。)
本質上,密鑰存儲在javax.net.ssl.keyStore用于包含私鑰和證書,而javax.net.ssl.trustStore意味著在遠程方顯示證書時包含您愿意信任的CA證書。在某些情況下,它們可以是同一個商店,盡管使用不同的存儲(尤其是基于文件的存儲)通常是更好的做法。
一般來說Djavax.net.ssl.keyStore和Djavax.net.ssl.trustStore一般就指向?$JAVA_HOME/lib/security/cacerts這個文件夾:
一種方式是通過在啟動參數中指定,如下:
- java -Djavax.net.ssl.trustStore=yourTruststore.jks -Djavax.net.ssl.trustStorePassword=12345
還是一種就是通過程序中指定Properties參數進行加載,不過一定要在請求發出之前進行加載,可以參考我的這篇文章
SpringBoot事件與監聽機制_人工智的博客-CSDN博客使用監聽實現,如下:
System.setProperty("javax.net.ssl.trustStore",?"truststore的絕對路徑或者相對路徑");
System.setProperty("javax.net.ssl.trustStorePassword",?"truststore密碼");
System.setProperty("javax.net.ssl.keyStore",?"keystore的絕對路徑或者相對路徑");
System.setProperty("javax.net.ssl.keyStorePassword",?"keystore密碼");
代碼類似這樣:
ath keystore = Files.createTempFile(null, null); try (InputStream stream = getClass().getResourceAsStream("/cacerts")) {Files.copy(stream, keystore); }System.setProperty("javax.net.ssl.trustStore", keystore.toString());怎么忽略ignore https 認證:
通過在httpClient call https接口之前先調用如下代碼即可忽略https認證
private static DefaultHttpClient httpClientTrustingAllSSLCerts() throws NoSuchAlgorithmException, KeyManagementException {DefaultHttpClient httpclient = new DefaultHttpClient();SSLContext sc = SSLContext.getInstance("SSL");sc.init(null, getTrustingManager(), new java.security.SecureRandom());SSLSocketFactory socketFactory = new SSLSocketFactory(sc);Scheme sch = new Scheme("https", 443, socketFactory);httpclient.getConnectionManager().getSchemeRegistry().register(sch);return httpclient; } private static TrustManager[] getTrustingManager() {TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {@Overridepublic void checkClientTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {}@Overridepublic void checkServerTrusted(java.security.cert.X509Certificate[] x509Certificates, String s) throws CertificateException {}@Overridepublic java.security.cert.X509Certificate[] getAcceptedIssuers() {return null;}} };return trustAllCerts; }再補充一點單項認證和雙向認證的區別
單向認證;
1、客戶端保存著服務端的證書并信任該證書即可
2、https一般是單向認證,這樣可以讓絕大部分人都可以訪問你的站點。
雙向認證
1、先決條件是有兩個或兩個以上的證書,一個是服務端證書,另一個或多個是客戶端證書。
2、服務端保存著客戶端的證書并信任該證書,客戶端保存著服務端的證書并信任該證書。這樣,在證書驗證成功的情況下即可完成請求響應。
3、雙向認證一般企業應用對接。
springboot配置安裝證書
前面說那么多,springboot其實都給我們解決好了,因為springboot有自帶的tomcat,直接把證書打到這個tomcat容器中了,不同于上面的java實現,tomcat容器有對應https的實現,將jks或者pfx文件復制到SpringBoot的resource目錄中:
(2)在application.yml中配置以下信息(pkcs12格式)
server:port: 443ssl:key-store: classpath:***.pfxkey-store-password: keystore的密碼默認是changeit,每個人都有自己的,keytool生成jks時會要求你輸入,那個時候記下來不要忘記了key-store-type: PKCS12?如果是properties文件的話如下(這次以jks為例,也可以換成pkcs12):
# 單向認證開啟(服務端證書,我自己作為服務端拿自己證書安裝) server.ssl.key-store=文件地址 server.ssl.key-store-password=123456 server.ssl.key-alias=sslServer server.ssl.keyStoreType=JKS # (我自己作為客戶端,拿服務端證書安裝(只包含服務端公鑰的證書文件)) server.ssl.trust-store-password=123456 server.ssl.client-auth=need server.ssl.trust-store-type=JKS server.ssl.trust-store-provider=SUN需要注意的是,server.ssl.client-auth有三個可配置的值:none、want和need。雙向驗證應該配置為need;none表示不驗證客戶端;want表示會驗證,但不強制驗證,即驗證失敗也可以成功建立連接。
客戶端測試代碼:
private final static String TEST_URL = "https://127.0.0.1:7090/server/ssl";@Testpublic void getHKVesselTrip() throws Exception {// 客戶端證書類型KeyStore clientStore = KeyStore.getInstance("PKCS12");// 加載客戶端證書,即自己的私鑰clientStore.load(new FileInputStream("E:\\learning-demo\\sslClient.p12"),"123456".toCharArray());// 創建密鑰管理工廠實例KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());// 初始化客戶端密鑰庫kmf.init(clientStore, "123456".toCharArray());KeyManager[] kms = kmf.getKeyManagers();// 創建信任庫管理工廠實例TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());// 信任庫類型KeyStore trustStore = KeyStore.getInstance("JKS");// 加載信任庫,即服務端公鑰trustStore.load(new FileInputStream("D:\\jdk\\jre\\lib\\security\\cacerts"),"changeit".toCharArray());// 初始化信任庫tmf.init(trustStore);TrustManager[] tms = tmf.getTrustManagers();// 建立TLS連接SSLContext sslContext = SSLContext.getInstance("TLS");// 初始化SSLContextsslContext.init(kms, tms, new SecureRandom());SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();try {HttpGet httpget = new HttpGet(TEST_URL);System.out.println("executing request" + httpget.getRequestLine());CloseableHttpResponse response = httpclient.execute(httpget);try {HttpEntity entity = response.getEntity();if (entity != null) {System.out.println(EntityUtils.toString(entity));}} finally {response.close();}} finally {httpclient.close();}}具體可參考這篇文章:【HTTPS】Spring Boot客戶端與服務端單向認證和雙向認證實例_Dream it Possible-CSDN博客_客戶端服務端雙向認證
原理參考此文:springboot SSL雙向驗證原理及配置_愛學習的果子君的博客-CSDN博客_springboot ssl驗證
使用java程序調用https繞開客戶端證書可信校驗:JAVA利用HttpClient進行HTTPS接口調用 - 路常有 - 博客園
httpclient能同時支持http和https的原理:HttpClient實現https調用 - 好奇成傳奇 - 博客園
springboot同時支持http和https配置:spring cloud/spring boot同時支持http和https訪問 - 涼瓜皮 - 博客園
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的HTTPS和HTTPS证书的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: classpath和读取resource
- 下一篇: 网络调试指令ping、telnet、cu