Keytool設定 Tomcat的HTTPS雙向認證

2022-06-10 21:00:34

Keytool設定 Tomcat的HTTPS雙向認證



證書生成

keytool 簡介

Keytool是一個Java資料證書的管理工具, Keytool將金鑰(key)和證書(certificates)存在一個稱為keystore的檔案中。
在keystore裡,包含兩種資料:

  • 金鑰實體(Key entity)——金鑰(secret key)又或者是私鑰和配對公鑰(採用非對稱加密)
  • 可信任的證書實體(trusted certificate entries)——只包含公鑰

我們常說的證書就是就是上面的公鑰,公鑰是公開給其它人使用的

  • 證書字尾解釋
    • jks 是Java的keytool證書工具支援的證書私鑰格式;
    • pfx 是微軟支援的私鑰格式(p12是pfx的新格式);
    • cer / crt 是證書的公鑰格式(cer是crt證書的微軟形式)
    • csr 數位憑證簽名請求檔案(Cerificate Signing Request)

Tips:

  • .der .cer : 此證書檔案是二進位制格式,只含有證書資訊,不包含私鑰。
  • .crt : 此證書檔案是二進位制格式或文字格式,一般為文字格式,功能與 .der.cer 證書檔案相同。
  • .pem : 此證書檔案一般是文字格式,可以存放證書或私鑰,或者兩者都包含。 .pem 檔案如果只包含私鑰,一般用 .key 檔案代替。
  • .pfx .p12 : 此證書檔案是二進位制格式,同時包含證書和私鑰,且一般有密碼保護。
  • .keystore .truststore : 兩者本質都是keystore,都是儲存金鑰的容器:
    • 不過兩者存放的金鑰所有者不同,keystore是儲存自己的公鑰和私鑰而,truststore是儲存自己信任物件的公鑰。約定通過檔名稱區分型別以及用途
    • truststore 是必須的,如果我們沒有顯式的指定,那麼java會預設指定為 $JAVA_HOME/lib/security/cacerts 這個檔案
    • java 在jdk 中已經預設在 $JAVA_HOME/lib/security/cacerts 這個檔案中預置了常用的證書
  • 不同語言需要的證書格式並不一致,比如說Java採用jks,.Net採用pfx和cer,Php則採用pem和cer;
  • 區別證書的不是字尾名,而是檔案的格式和內容。

keytool 命令詳解

  • 金鑰和證書管理工具

    -certreq            生成證書請求
    -changealias        更改條目的別名
    -delete             刪除條目
    -exportcert         匯出證書(簡寫 export)
    -genkeypair         生成金鑰對(簡寫 genkey)
    -genseckey          生成金鑰
    -gencert            根據證書請求生成證書
    -importcert         匯入證書或證書鏈(簡寫 import)
    -importpass         匯入口令
    -importkeystore     從其他金鑰庫匯入一個或所有條目
    -keypasswd          更改條目的金鑰口令
    -list               列出金鑰庫中的條目
    -printcert          列印證書內容
    -printcertreq       列印證書請求的內容
    -printcrl           列印 CRL 檔案的內容
    -storepasswd        更改金鑰庫的儲存口令
    

Tips:

  • 使用 ketytool --help 獲取所有可用命令

  • 使用 keytool -command_name -help 來獲取 command_name 的用法

  • 常用引數

    -genkey         產生金鑰對(genkeypair 簡寫);表示要建立一個新的金鑰;alias和keystore預設時,在使用者主目錄中建立一個」.keystore」檔案,且別名為mykey,包含使用者的公鑰、私鑰證書
    -alias          產生證書別名,和keystore關聯的唯一別名,不區分大小寫(預設 `mykey`)
    -keystore       指定金鑰庫檔案的名稱(預設在使用者主目錄建立證書庫)
    -keyalg         指定金鑰的演演算法(可選擇金鑰演演算法:`RSA`、`DSA`、`EC`,預設`DSA`)
    -keysize        指定金鑰長度(與keyalg預設對應關係:`RSA=2048`、`DSA=2048`、`EC=256`)
    -sigalg         指定簽名演演算法(MD5和 SHA1的簽名演演算法已經不安全)
    -validity       指定證書有效期天數(預設 `90`天)
    -storepass      指定金鑰庫口令,推薦與keypass一致(獲取keystore資訊所需的密碼)
    -storetype      指定金鑰庫的型別,可用型別為:JKS、PKCS12等。(jdk9以前,預設為JKS。自jdk9開始,預設為PKCS12)
    -keypass        指定別名條目口令(私鑰的密碼)
    -dname          指定證書發行者資訊(其中 CN 要和伺服器的域名相同,本地測試則使用localhost,其他的可以不填)
    -list           顯示金鑰庫中的證書資訊
    -v              詳細輸出,顯示金鑰庫中的證書詳細資訊
    -file           指定匯出或匯出的檔名
    -export         將別名指定的證書匯出到檔案(exportcert 簡寫)
    -import         將已簽名數位憑證匯入金鑰庫(importcert 簡寫)
    -printcert      檢視匯出的證書資訊
    -delete         刪除金鑰庫中某條目
    -keypasswd      修改金鑰庫中指定條目口令
    -storepasswd    修改keystore口令
    -ext            X.509 擴充套件
    
  • 所有密碼長度必須大於或等於 6 位

  • keyalg 指定加密演演算法;可以選擇的金鑰演演算法有:RSA、DSA(預設)、EC。

  • sigalg 指定簽名演演算法(MD5和 SHA1的簽名演演算法已經不安全):

    • keyalg = RSA 時,簽名演演算法有:MD5withRSA、SHA1withRSA、SHA256withRSA(預設)、SHA384withRSA、SHA512withRSA
    • keyalg = DSA 時,簽名演演算法有:SHA1withDSA、SHA256withDSA(預設)
  • dname 表明了金鑰的發行者身份(Distinguished Names)

    • CN = 域名或IP(Common Name) 注:生成伺服器證書時,CN要和伺服器的域名相同,本地測試則使用localhost,其他的可以不填(使用者端證書無要求)
    • OU = 組織單位名稱(Organization Unit)
    • O = 組織名稱(Organization Name)
    • L = 城市或區域名稱(Locality Name)
    • ST = 州或省份名稱(State Name)
    • C = 國家的簡寫(Country,CN 代表中國)

建立證書

建立祕鑰庫(keystore),祕鑰庫是儲存一個或多個金鑰條目的檔案,每個金鑰條目應該以一個別名標識,它包含金鑰和證書相關資訊。

  • Usage:

    keytool -genkey 
            -alias <alias> 
            -keyalg RSA 
            [-sigalg SHA256withRSA] 
            [-keysize 2048] 
            -keypass <keypasswd> 
            -keystore <keystore_file> 
            -storetype JKS|PKCS12 
            -storepass <keystore_passwd> 
            -validity 3650 
            -dname "CN=github.com,OU=github.com,Inc.,O=Github, Inc.,L=San Francisco,ST=California,C=US" 
            -ext SAN=dns:github.com,dns:www.github.com,ip:127.0.0.1 
    
  • Options:

    -genkey     產生金鑰對(genkeypair 簡寫)
    -alias      證書別名;和keystore關聯的唯一別名,這個alias通常不區分大小寫(預設`mykey`)
    -keyalg     指定加密演演算法,RSA:非對稱加密(預設`DSA`)
    -sigalg     指定簽名演演算法,可選;
    -keysize    指定金鑰長度,可選;
    -keypass    指定別名條目口令(私鑰的密碼)
    -storetype  生成證書型別,可用的證書庫型別為:JKS、PKCS12等。
    -keystore   指定產生的金鑰庫的位置;
    -storepass  指定金鑰庫的存取口令,推薦與keypass一致
    -validity   證書有效期天數;(預設為 90天)
    -dname      表明了金鑰的發行者身份(Distinguished Names)生成證書時,其中 CN 要和伺服器的域名相同,本地測試則使用localhost,其他的可以不填
    -ext        X.509 擴充套件
    

Tips:

  • 此處需要注意:MD5和SHA1的簽名演演算法已經不安全;
  • 如果Tomcat所在伺服器的域名不是「localhost」時,瀏覽器會彈出警告視窗,提示使用者證書與所在域不匹配。
    • 伺服器證書 dname的 CN應改為對應的域名,如「www.github.com」;在本地做開發測試時,CN應填入「localhost」;
    • 使用者端證書 dname的 CN可以是任意值,且不用使用 -ext擴充套件。

建立證書栗子

  1. 生成伺服器證書

    keytool -genkey -alias server -keyalg RSA -keypass 123456 -keystore ~/ssl/tomcat.jks [-storetype JKS] -storepass 123456 -validity 3650 -dname "CN=localhost" -ext SAN=ip:127.0.0.1

  2. 生成使用者端證書,以便讓伺服器來驗證它。為了能將證書順利匯入至IE和Firefox,證書格式應該是PKCS12(使用者端的CN可以是任意值)

    keytool -genkey -alias client -keyalg RSA -keypass 123456 -keystore ~/ssl/client.p12 -storetype PKCS12 -storepass 123456 -validity 3650 -dname "CN=client"


匯出證書資訊

此證書檔案不包含私鑰;分為自簽名證書和認證證書,下面分別介紹了兩中證書的生成方式

  • 認證證書與匯出的伺服器自簽名證書作用一致,使用時取其中一種證書即可。兩者主要區別為是否經證書機構認證;
  • 使用自簽名證書則無需生成證書籤名請求(CSR),使用認證證書則無需匯出伺服器自簽名證書;
  • 大部分認證證書都是收費的;

匯出自簽名證書

自簽名證書沒有經過證書認證機構進行認證,但並不影響使用,我們可以使用相應的命令對證書進行匯出;

  • Usage:

    keytool -export 
            -alias <alias> 
            -keystore <keystore_file> 
            -storepass <keystore_passwd> 
            -file <file_cer>    
            [-rfc] 
    
  • Options:

    -export     執行證書匯出操作(exportcert 簡寫)
    -alias      金鑰庫中的證書條目別名(jks裡可以儲存多對公私鑰檔案,通過別名指定匯出的公鑰證書)
    -keystore   指定金鑰庫檔案
    -storepass  金鑰庫口令
    -file       匯出檔案的輸出路徑
    -rfc        使用Base64格式輸出(輸出pem編碼格式的證書,文字格式),不適用則匯出的證書為DER編碼格式
    
匯出證書栗子
  1. 匯出伺服器證書

    此處為伺服器的自簽名證書匯出, 如果需要使用認證證書,則生成證書籤名請求

    keytool -export -alias server -keystore ~/ssl/tomcat.jks -storepass 123456 -file ~/ssl/server.cer

  2. 匯出使用者端證書

    雙向認證: 伺服器端信任使用者端,由於不能直接將PKCS12格式的證書庫匯入,所以必須先把使用者端證書匯出為一個單獨的CER檔案

    keytool -export -alias client -keystore ~/ssl/client.p12 -storepass 123456 -file ~/ssl/client.cer -rfc

獲取認證證書(生成證書籤名請求)

如果想得到證書認證機構的認證,則不使用上述的自簽名證書,需要使用步驟匯出數位憑證並簽發申請(Cerificate Signing Request),經證書認證機構認證並頒發後,再將認證後的證書匯入本地金鑰庫與信任庫。

  • Usage:

    keytool -certreq 
            -alias <alias> 
            -keystore <keystore_file> 
            -storepass <keystore_passwd> 
            -file <file_csr> 
    
  • Options:

    -certreq    執行證書籤發申請匯出操作
    -alias      金鑰庫中的證書條目別名
    -keystore   金鑰庫檔名稱
    -storepass  金鑰庫口令
    -file       輸出的csr檔案路徑
    
生成證書籤名請求栗子
  1. 生成證書籤名請求(CSR)

    keytool -certreq -alias server -keystore ~/ssl/tomcat.jks -storepass 123456 -file ~/ssl/certreq.csr

  2. 檢視生成的CSR證書請求

    keytool -printcertreq -file certreq.csr


匯入證書庫

雙向認證: 將各自的公鑰證書分別匯入對方的信任庫,使使用者端和伺服器端相互信任。

  • Usage:

    keytool -import 
            [-trustcacerts] 
            -alias <alias_cer> 
            -keystore <keystore_file>
            -storepass <keystore_passwd> 
            -file <file_cer> 
    
  • Options:

    -import     執行證書匯入操作(importcert 簡寫)
    -alias      指定匯入金鑰庫中的證書別名(指定的條目別名不能與金鑰庫中已存在的條目別名重複(匯入簽發證書除外))
    -trustcacerts    將證書匯入信任庫(信任來自 cacerts 的證書)
    -keystore   金鑰庫名稱
    -storepass  金鑰庫口令
    -file       輸入檔名
    

匯入證書栗子

  1. 安裝伺服器證書(將伺服器公鑰證書匯入使用者端)

    雙向認證: 使用者端信任伺服器端: 在客戶機器上雙擊證書檔案完成匯入操作(window中匯入)

    • 將伺服器公鑰證書 server.cer 發往使用者端機器 >> 雙擊該證書進入「證書資訊」頁 >> 點選【安裝證書】進入「證書匯入嚮導」首頁 >> 點選【下一步】>> 選中【將所有的證書都放入下列儲存】,然後單擊【瀏覽】 >> 選擇【受信任的根證書頒發機構】b並點選【確定】 >> 點選【下一步】 >> 點選【完成】。然後彈出提示【匯入完成】。
    • 將使用者端證書 client.p12 發往使用者端機器 >> 雙擊該證書進入「證書匯入嚮導」首頁 >> 點選【下一步】>> 點選【下一步】>> 輸入證書密碼(keystore密碼)並點選【下一步】 >> 點選【下一步】 >> 點選【完成】。然後彈出提示【匯入完成】。
  2. 證書匯入信任庫(將使用者端公鑰證書匯入信任庫)

    雙向認證: 伺服器端信任使用者端:

    keytool -import -alias clientCert -keystore ~/ssl/truststore.jks -storepass 123456 -file ~/ssl/client.cer

    此步驟會生成信任證書 truststore.jks檔案, 檔案存放需要信任的公鑰證書,如使用者端證書(也可以將 keystore值改為伺服器金鑰庫,即tomcat.jks。此時的tomcat.jks 就同時是服務的金鑰庫和信任庫)


檢視證書

  • Usage:

    # 檢視單個證書(cer | crt)
    keytool -printcert -file <cert_file> [-v|-rfc]
    
    # 檢視金鑰庫中的證書條目
    keytool -list [-alias <alias_name>] -keystore <keystore_file> -storepass <keystore_passwd> [-v|-rfc]
    
    # 檢視生成的CSR證書請求
    keytool -printcertreq -file <certreq_file>     
    
  • Options:

    -alias      金鑰庫中的證書條目別名;
    -keystore   指定金鑰庫檔案;
    -storepass  金鑰庫口令;
    -printcert  執行證書列印命令;
    -list       預設情況下,命令列印證書的 MD5 指紋。
        而如果指定了 -v 選項,將以可讀格式列印證書,
        如果指定了 -rfc 選項,將以可列印的編碼格式輸出證書。
    

檢視栗子證書

  1. 檢視證書資訊

    keytool -printcert -file ~/ssl/client.cer [-v|-rfc]

  2. 檢視金鑰庫

    keytool -list -keystore ~/ssl/tomcat.jks -storepass 123456 -v

  3. 檢視base64的內容(即PEM編碼)

    keytool -list -keystore ~/ssl/tomcat.jks -storepass 123456 -rfc


其他keytool命令

# 刪除keystore裡面指定證書條目
keytool -delete -alias <alias> -keystore <keystore_file> -storepass <keystore_passwd>

# 修改條目別名
keytool -changealias -keystore <keystore_file> -alias <old_alias> -destalias <new_alias>

# 修改條目密碼
keytool -keypasswd -alias <alias> -keypass <old_keypasswd> -new <new_keypasswd> -keystore <keystore_file> -storepass <keystore_passwd>

# 修改keysore密碼
keytool -storepasswd -new <new_storepasswd> -keystore <keystore_file> -storepass <old_storepasswd>


# 列出信任的CA證書(檢視 JVM的信任庫中的證書,storepass 預設為changeit)
## 該證書檔案存在於JAVA_HOME\jre\lib\security目錄下,是Java系統的CA證書倉庫,可以用 'alias' 來檢視證書是否真的匯入到JVM中
keytool -list -v [-alias clientCer] -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

# 匯入新的CA到信任證書,匯入到 JRE的信任證書庫
## 常出現的異常:「未找到可信任的證書」  -- 主要原因為在使用者端未將伺服器下發的證書匯入到JVM中。
keytool -import -trustcacerts -alias clientCer -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -file ~/ssl/client.cer

Tomcat服務認證設定

開啟Tomcat_HOME/conf/server.xml,找到如下原註釋內容,並修改如下:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
    maxThreads="150" scheme="https" secure="true"
    clientAuth="true" sslProtocol="TLS"
    keystoreFile="~/ssl/tomcat.jks" keystorePass="123456"
    truststoreFile="~/ssl/truststore.jks" truststorePass="123456"
/>

Tips:

  • 其中 clientAuth 指定是否需要驗證使用者端證書
  • false : 表示單向SSL驗證,即伺服器端認證;
  • true : 表示強制雙向SSL驗證,必須驗證使用者端證書;
  • want : 表示可以驗證使用者端證書,但如果使用者端沒有有效證書,也不強制驗證。
  • 如果設定了clientAuth="true",則需要強制驗證使用者端證書。可通過雙擊 p12 檔案將證書匯入至瀏覽器;
  • 瀏覽器的HTTP預設埠為 80 , HTTPS預設埠為 443
  • keystoreFile /keystorePass : 伺服器證書檔案和密碼;
  • truststoreFile /truststorePass : 信任證書檔案和密碼;用來驗證使用者端的。

SSL單向證書認證設定

  1. 建立伺服器證書
  2. 匯出伺服器公鑰證書
  3. 將伺服器公鑰證書匯入使用者端(使用者端信任伺服器)
  4. 設定 Tomcat
    開啟Tomcat_HOME/conf/server.xml,找到如下原註釋內容,並修改如下:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
    maxThreads="150" scheme="https" secure="true"
    clientAuth="false" sslProtocol="TLS"
    keystoreFile="~/ssl/tomcat.jks" keystorePass="123456"()
/>

SSL雙向證書認證設定

  1. 建立伺服器證書,建立使用者端證書

  2. 匯出伺服器公鑰證書,匯出使用者端公鑰證書

  3. 將伺服器公鑰證書匯入使用者端(使用者端信任伺服器)

  4. 將使用者端公鑰證書匯入信任庫(伺服器信任使用者端)

  5. 設定 Tomcat,並開啟雙向認證():
    開啟Tomcat_HOME/conf/server.xml,找到如下原註釋內容,並修改如下:

    <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
        maxThreads="150" scheme="https" secure="true"
        clientAuth="true" sslProtocol="TLS"
        keystoreFile="~/ssl/tomcat.jks" keystorePass="123456"
        truststoreFile="~/ssl/truststore.jks" truststorePass="123456"
    />
    

設定Tomcat服務 HTTP自動跳轉到 HTTPS(按需選配)

開啟Tomcat_HOME/conf/web.xml,在 與 加入如下程式碼:

<login-config> 
    <!-- Authorization setting for SSL --> 
    <auth-method>CLIENT-CERT</auth-method> 
    <realm-name>Client Cert Users-only Area</realm-name> 
</login-config> 
<security-constraint> 
    <!-- Authorization setting for SSL --> 
    <web-resource-collection > 
        <web-resource-name >SSL</web-resource-name> 
        <url-pattern>/*</url-pattern> 
    </web-resource-collection> 
    <user-data-constraint> 
        <transport-guarantee>CONFIDENTIAL</transport-guarantee> 
    </user-data-constraint> 
</security-constraint> 

測試

  1. 啟動 Tomcat專案
  2. 存取 專案地址,本地設定如: https://localhost:8443/
  3. 如果遇到「不安全」的提示,可能是使用者端未安裝伺服器證書

常見問題

瀏覽器存取時提示:

  1. 此伺服器無法證實它是「192.168..」 - 您計算機的作業系統不信任其安全證書 。。。
    --使用者端未匯入伺服器證書

  2. 此伺服器無法證實它就是「192.168..」 - 它的安全證書沒有指定主題備用名稱 。。。
    --生成伺服器證書庫未使用 -ext引數

  3. 「192.168..」不接受您的登入證書,或者您可能沒有提供登入證書。。。
    --Tomcat設定未指定信任證書庫(truststore)



Reference