說得直白點(diǎn),數(shù)字證書(Digital Certificate)即通過對通信雙方(比如瀏覽器和服務(wù)器)之間傳輸?shù)臄?shù)據(jù)進(jìn)行加密以達(dá)到安全通信的目的。除了加密功能外,數(shù)字證書還用于身份認(rèn)證,即數(shù)字證書就像是居民身份證一樣,能夠向別人證明“你確是你”。

一點(diǎn)點(diǎn)理論基礎(chǔ)

我們都知道,HTTP協(xié)議對數(shù)據(jù)采用明文傳輸,瀏覽器和服務(wù)器之間的所有數(shù)據(jù)傳輸都赤裸裸地暴露在互聯(lián)網(wǎng)上,包括你在登陸某個網(wǎng)站時輸入的密碼。為了解決這個問題,前人發(fā)明了對數(shù)據(jù)進(jìn)行加密傳輸?shù)腍TTPS協(xié)議,該協(xié)議又建立在SSL/TLS協(xié)議之上。SSL/TLS位于HTTPS與TCP協(xié)議之間,是實(shí)現(xiàn)數(shù)據(jù)加密的核心協(xié)議,其本質(zhì)上講是對TCP協(xié)議的一層封裝。由此可見,SSL/TLS其實(shí)不止可以用于HTTP,任何采用TCP協(xié)議的數(shù)據(jù)通信都可以采用SSL/TLS進(jìn)行傳輸,比如FTP。只是就當(dāng)前而言,SSL/TLS最為廣泛的應(yīng)用在于HTTPS。

在計(jì)算機(jī)密碼學(xué)里,存在著對稱加密和非對稱加密兩種加密方式,對稱加密即通信雙方均使用相同的密鑰,如果Alice要將密文發(fā)給Bob,那么她首先需要將密鑰發(fā)給Bob,那么問題來了——密鑰又通過什么方式能夠安全地發(fā)給Bob?為了解決這個問題,出現(xiàn)了非對稱加密算法,即加密采用一個密鑰,解密采用另一個密鑰,兩個密鑰組成一個密鑰對,由一個密鑰加密的數(shù)據(jù)只能由密鑰對中另一個密鑰才能解密,最典型的非對稱加密算法非RSA莫屬。RSA是目前最有影響力的公鑰加密算法,該算法基于一個十分簡單的數(shù)論事實(shí):將兩個大素?cái)?shù)相乘十分容易,但那時想要對其乘積進(jìn)行因式分解卻極其困難,因此可以將乘積公開作為加密密鑰,即公鑰(Public Key),而兩個大素?cái)?shù)組合成私鑰(Private Key)。公鑰是可發(fā)布的供任何人使用,私鑰則為自己所有,供解密之用。SSL/TLS便使用了非對稱加密。

對于網(wǎng)站服務(wù)器來說,我們可以為其生成一個密鑰對,其中公鑰可以被所有瀏覽器任意下載,但是私鑰只能又對服務(wù)器可見。當(dāng)瀏覽器通過HTTPS訪問網(wǎng)站時,瀏覽器首先下載到服務(wù)器的公鑰,然后再通過公鑰對所發(fā)送的數(shù)據(jù)進(jìn)行加密,再傳給服務(wù)器,服務(wù)器收到加密數(shù)據(jù)后,通過對應(yīng)的私鑰進(jìn)行解密。服務(wù)器在返回?cái)?shù)據(jù)時,使用私鑰進(jìn)行加密,瀏覽器取到數(shù)據(jù)后再通過公鑰進(jìn)行解密。由此一來,即保證了通信雙方數(shù)據(jù)的加密傳輸,又解決了密鑰的分發(fā)問題。整個SSL/TLS的工作原理比上述要復(fù)雜很多,感興趣的讀者可以參考SSL/TLS。

但是,這樣依然會存在問題——瀏覽器如何知道所下載的公鑰的確是來自于其要訪問的服務(wù)器的呢?惡意攻擊者完全可以在他們之間冒充服務(wù)器向?yàn)g覽器發(fā)送一個冒牌的公鑰,你在完全沒有感知的情況下相信了該公鑰,這個冒牌貨便肆無忌憚地盜取你的密碼,偷走你銀行卡里的存款(此所謂中間人攻擊)。如果有一種方式能夠讓瀏覽器事先驗(yàn)證所下載公鑰的確來自于其正在訪問的網(wǎng)站就好了——即本文一開始提到的證明“你的確是你”。

答案是肯定的,就是我們今天要講的主角——數(shù)字證書。

還是拿居民身份證為例,身份證之所以能夠證明你的身份,是因?yàn)樗怯晒簿诸C發(fā)的,任何人需要使用身份證來驗(yàn)證你的身份時,比如火車票自動售賣機(jī)或者銀行柜臺的業(yè)務(wù)辦理員,他們都需要無條件的相信公安局的權(quán)威作用。也就是說,如果能夠找到一個權(quán)威的第三方同時被當(dāng)事雙方所信任,那么問題就解決了。類比起來,數(shù)字證書便充當(dāng)了居民身份證的作用,它由一個第三方的權(quán)威機(jī)構(gòu)頒發(fā)——證書權(quán)威機(jī)構(gòu)(Certificate Authority,CA)。數(shù)字證書里面包含有網(wǎng)站的身份信息以及用于網(wǎng)站的公鑰,即既能對網(wǎng)站的真實(shí)性提供證明,又能提供對數(shù)據(jù)的加密傳輸。

在有數(shù)字證書的參與下,整個通信過程大致如下:網(wǎng)站首先向CA機(jī)構(gòu)購買一個數(shù)字證書,該證書里有網(wǎng)站的公鑰、網(wǎng)站的域名和CA機(jī)構(gòu)的數(shù)字簽名。瀏覽器不再直接下載網(wǎng)站的公鑰,而是下載得到網(wǎng)站的數(shù)字證書。瀏覽器需要做的第一件事便是驗(yàn)證數(shù)字證書的真實(shí)性,操作系統(tǒng)或者瀏覽器在安裝時便安裝有常見CA機(jī)構(gòu)自己的證書,比如Verisign、Symantic等,這些證書是瀏覽器無條件信任的,他們里面的公鑰便用于對網(wǎng)站證書的驗(yàn)證——通過CA證書里面的公鑰計(jì)算網(wǎng)站證書的數(shù)字簽名,當(dāng)計(jì)算出的數(shù)字簽名與網(wǎng)站證書里提供的數(shù)字簽名相同時,表示該網(wǎng)站證書的確為CA機(jī)構(gòu)所頒發(fā),也即此時所訪問的網(wǎng)站的確不是冒牌的。

當(dāng)然,真實(shí)的數(shù)字證書的認(rèn)證過程比上述要復(fù)雜得多,比如,除了驗(yàn)證證書的數(shù)字簽名外,還需檢查網(wǎng)站證書里的網(wǎng)站域名是否與當(dāng)前正在訪問的域名一致。另外,CA機(jī)構(gòu)是分層級的,包括根證書(Root Certificate)、中間證書(Intermediate Certificate)以及最底層的網(wǎng)站證書。其中根證書簽署中間證書,中間證書在簽署最底層的網(wǎng)站證書,由此組成一個證書鏈(Certificate Chain)。整個對證書的頒發(fā)、管理、認(rèn)證組成了一整套基礎(chǔ)設(shè)施——PKI

獲取證書

獲取證書的常規(guī)方式是向CA權(quán)威機(jī)構(gòu)(公司)購買,這些證書一般來講價(jià)格都不便宜,當(dāng)然,一些公司為了廣告宣傳會提供免費(fèi)的證書,比如阿里云和騰訊云都有免費(fèi)的證書。另外,有一個叫Let's Encrypt的組織完全免費(fèi)地向網(wǎng)站提供數(shù)組證書。再者,作為開發(fā)者,你完全可以自己生成一個自簽名(Self-Signed)的證書用于開發(fā)過程,當(dāng)然,這種證書并不是由CA機(jī)構(gòu)頒發(fā)的,因此不能用于生成環(huán)境。

使用Java Keytool生成自簽名證書

Java提供一個命令行工具keytool用于創(chuàng)建和管理密鑰和數(shù)字證書。通過keytool生成自簽名證書如下:

keytool -genkey -keyalg RSA -alias self-signed -keystore keystore.jks -storepass password -validity 360 -keysize 2048

該命令表示采用RSA算法生成一個2048位的密鑰對,然后由為密鑰對中的公鑰生成數(shù)字證書,證書的有效期為360天。最后將密鑰對和證書作為一條記錄(Entry)保存到keystore.jks文件中,文件訪問密碼設(shè)為password,為該條記錄取個別名為self-signed以便后續(xù)定位用。

該命令會讓我們回答一系列問題:

What is your first and last name?
  [Unknown]:  www.mydomain.com
What is the name of your organizational unit?
  [Unknown]:  it department
What is the name of your organization?
  [Unknown]:  my company
What is the name of your City or Locality?
  [Unknown]:  Chengdu
What is the name of your State or Province?
  [Unknown]:  Sichuan
What is the two-letter country code for this unit?
  [Unknown]:  CNIs CN=www.mydomain.com, OU=it department, O=my company, L=Chengdu, ST=Sichuan, C=CN correct?
  [no]:  yes

Enter key password for <self-signed>
    (RETURN if same as keystore password):

這里第一個問題What is your first and last name?最為重要,如果你要將此時生成的密鑰用于向CA機(jī)構(gòu)購買證書(參考下文的CSR),那么該問題應(yīng)該回答你自己的網(wǎng)站域名。

如何購買證書

由于證書包含了你自己的公鑰,所以在購買之前你需要自己生成一個密鑰對,然后將密鑰對中的公鑰提取出來,再和一些你網(wǎng)站的基本信息(比如域名等)一并組裝成一個證書簽署請求(Certificate Signing Request,CSR),將該請求(文件)發(fā)給CA機(jī)構(gòu),CA機(jī)構(gòu)將根據(jù)CSR中的信息為你生成一個數(shù)字證書。

在java中,我們依然可以通過keytool命令為既有的密鑰記錄生成CSR,比如要為上文中別名為self-signed的記錄生成CSR命令如下:

keytool -certreq -alias self-signed -keyalg RSA -file yourdomain.csr -keystore keystore.jks

當(dāng)從CA機(jī)構(gòu)購買得到證書之后,我們可以通過keytool命令將證書導(dǎo)入到原來的自簽名記錄中,原來的自簽名證書將被覆蓋掉。假設(shè)購買得到的證書文件為certificate.cer,導(dǎo)入命令如下:

keytool -import -alias self-signed -file certificate.cer -keystore keystore.jks

在導(dǎo)入了購買所得的證書之后,別名self-signed便不是那么合適了,此時我們可以將其改名:

keytool -changealias -keystore keystore.jks -alias self-signed -destalias new-alias

上述創(chuàng)建密鑰對以及CSR的過程對于很多人來說可能并不是一件簡單的事情,因此有些公司(比如阿里云)將整個過程簡化了——由公司負(fù)責(zé)幫我們生成密鑰對,然后依然由公司幫我們生成CSR,最后將所生成的數(shù)字證書、私鑰一并返回,而我們只需要提供諸如網(wǎng)站域名這樣的一些基本信息即可。

證書格式

在上文中,我們接觸到了Java的jks文件,jks即Java KeyStore的縮寫。在Java中證書通過KeyStore對象表示并存放于keystore文件中。keystore文件主要包含了兩類記錄,一種是我們上文中所創(chuàng)建的PrivateKeyEntry,一種是TrustedCertificateEntry。PrivateKeyEntry用于存放私鑰與證書的組合,而TrustedCertificateEntry只用于存放數(shù)字證書(不包含私鑰)。雖然兩種記錄都可以存放證書,但是他們的用途是有區(qū)別的,PrivateKeyEntry用于向別人證明你自己的身份,而TrustedCertificateEntry用于驗(yàn)證別人的身份,即如果你是一個網(wǎng)站需要向?yàn)g覽器證明自己,此時你應(yīng)該把證書放在PrivateKeyEntry中(就像上文一樣);而如果你是一個訪問網(wǎng)站的客戶端,比如需要通過HTTPS訪問網(wǎng)站提供的REST API接口,那么你需要將網(wǎng)站的證書放到TrustedCertificateEntry中。

在Java中,雖然PrivateKeyEntry和TrustedCertificateEntry可以同時放在一個keystore文件中,但是推薦的做法是將他們分開存儲。比如JRE默認(rèn)有一個$JAVA_HOME/jre/lib/security/cacerts的keystore文件,里面便只存放了TrustedCertificateEntry,這些記錄為一些常見CA機(jī)構(gòu)的證書。

keystore文件只是Java的東西,除此之外,還有其他文件格式可以表示數(shù)字證書,并且在有些情況下他們之間是可以相互轉(zhuǎn)換的。

常見的證書格式文件有:

  • der, cer,二進(jìn)制文件,只含有證書,不含私鑰

  • pem,文本文件,可以同時包含證書和私鑰,也可以存放公鑰

  • key,文本文件,如果pem中只包含私鑰,通常用key后綴替代

  • cert、crt,文本文件,如果pem中只包含了證書,通常用cert或者crt后綴表示

  • pfx、p12,二進(jìn)制文件,同時包含證書和私鑰

  • jks,二進(jìn)制文件,只用于Java,同時包含證書和私鑰

數(shù)字證書遵循X.509標(biāo)準(zhǔn),該標(biāo)準(zhǔn)定義了證書的數(shù)據(jù)結(jié)構(gòu),該數(shù)據(jù)結(jié)構(gòu)通過DER編碼便得到了二進(jìn)制的der文件,由于二進(jìn)制文件在人機(jī)間傳輸不便,對其進(jìn)行BASE64編碼便得到了pem文本文件,當(dāng)然pem文件不止用于存放證書,還可以用于存放公鑰和私鑰,比如由ssh-keygen命令生成的密鑰對便采用了pem文件格式。pem文件通常具有以下格式:

—–BEGIN CERTIFICATE—–
MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0
MRwHQYDVQQDDBZBZmZpcm1UcnVz......
—–END CERTIFICATE—–

pfx和p12是RSA公司制定的證書標(biāo)準(zhǔn)。

在Tomcat中配置證書

不同Tomcat版本中配置證書的方式不同,本文采用的是Tomcat 8.5.15版本。
在Tomcat中,主要通過配置jks文件來達(dá)到配置HTTPS的目的,當(dāng)然也可以直接配置pfx文件。

可以通過生成自簽名證書的方式得到的jks文件,如果證書是購買的,通常你不會直接拿到j(luò)ks文件,此時你很有可能得到pfx/p12文件或者是crt文件(通過你自己的CSR獲得,密鑰在你自己手中或者賣家會一并發(fā)給你)。

對于pfx文件,可以通過以下命令轉(zhuǎn)成jks文件:

keytool -importkeystore -srckeystore your.pfx -destkeystore your-name.jks -srcstoretype PKCS12 -deststoretype JKS

對于crt文件,通常來說是你知己手頭已經(jīng)有私鑰了,就像在上文中將證書導(dǎo)入到既有的keystore里面一樣,此時你只需要將crt證書文件通過keytool命令導(dǎo)入到原來的PrivateKeyEntry即可。

在配置Tomcat時,首先在`$TOMCAT_HOME/conf/server.xml中找到:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            ......        </SSLHostConfig>
    </Connector>

初始情況下,本段是被注釋掉的,解除注釋后,將其改為:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
            <Certificate certificateKeystoreFile="path/to/your.jks"
                         certificateKeystorePassword="your-password"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>

其中certificateKeystoreFile為jks文件,certificateKeystorePassword為該keystore文件的訪問密碼。

如果需要將HTTP自動跳轉(zhuǎn)到HTTPS,需要在項(xiàng)目的web.xml文件中加入:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Restricted URLs</web-resource-name>
    <url-pattern>/*</url-pattern>
  </web-resource-collection>
  <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint></security-constraint>

http://www.cnblogs.com/davenkin/p/digital-certificate.html