07.13 非對稱加密與安全證書看這一篇就懂了

前幾日做支付對接時,被對方文檔中的加密方式搞暈乎了一會。意識到證書加密方面的理解不夠深入,事後查閱參考資料補習一波。本文是根據期間的學習,以及長期以來的實踐做出的總結。

加密方式

密碼學是涉及數學、電子信息、計算機等多學科的一門重要學科,是現代互聯網安全的基石,也是目前如火如荼的區塊鏈技術的安全保障。概括來說,加密方式可歸結為不可逆加密與可逆加密。

不可逆加密

信息摘要(Message Digest)和安全散列(Secure Hash)算法屬於此類,常見的算法包括 MD5、SHA1、PBKDF2、bcrypt 等。此類算法可將任意大小的原始數據變換成規定長度的輸出,即獲取內容的數字指紋,常用於校驗原始內容是否被篡改。這類算法的主要特點是:

  • 不可逆性。除非窮舉等手段,原則上不存在根據密文推斷出原文的算法;
  • 雪崩效應。對輸入數據敏感,原始內容的極小改動會造成輸出的大差異;
  • 防碰撞性。原則上很難找到兩組不同的原文,經過加密後密文相同。

左耳朵耗子的“RSYNC 的核心算法”介紹了 MD5 算法在 rsync 中的具體應用。MD5 和 SHA1 已經被證實不安全(王小云教授在04年找到 MD5 迅速碰撞方法,谷歌在17年完成了 SHA1 的第一次碰撞),實踐中建議至少用 SHA-256 算法,或採用對算力不敏感的 scrypt、Argon2 等算法。

https://coolshell.cn/articles/7425.html

哈希算法(安全散列)的一個變種是 HMAC(Hash-based Message Authentication Code)算法,用於解決身份認證和防抵賴。HMAC 算法的輸入為一個密鑰(通信雙方共享)、一種哈希算法(常為經典哈希算法)和原始數據,輸出的內容格式取決於所採用的哈希算法。由於只有通信雙方知曉密鑰,所以可確認信息就是由對方發出。

可逆加密

哈希算法可保證通信中的數據不被篡改,而可逆加密算法是還原出明文的關鍵。可逆加密算法可分成三類:

  • 基於算法的加密算法,也被稱為古典加密算法,如 HTTP 認證中的 base64,比特幣生成地址用的 base58(公開的算法也可稱作編碼方式)。這類算法主要對原始內容進行置換和替換得到密文,安全性依賴於算法是否外洩;
  • 對稱加密算法,加密和解密使用同一個密鑰。對稱加密算法的出現標誌密碼學進入現代密碼學階段,密文的安全性從依賴於算法轉向依賴於密鑰。常見的對稱加密算法有 DES、3DES、AES;
  • 非對稱加密算法,加密和解密使用不同的密鑰。非對稱加密算法開創了密碼學的里程碑,解決了對稱加密過程中密鑰分發的安全問題,被認為現代密碼學最偉大的發明。常見的算法有 RSA、DH(Diffie-Hellman)、橢圓曲線算法(Elliptic curve cryptography,ECC)。

非對稱算法設計巧妙,但實際中要結合對稱加密使用。原因是某些算法不能加解密(DH、DSA),或者效率太低(RSA),或者能處理的數據大小有限制(RSA)。而對稱加密算法的有點是速度快、加密強度高。常用非對稱算法獲得共享密鑰,之後用對稱加密處理數據。本文的重點是非對稱加密及其衍生概念,下面逐一介紹。

公鑰、私鑰和證書

除算法外,非對稱加密中另外兩個重要的概念是公鑰和私鑰。公鑰對外公開,任何人均可持有和使用;私鑰自行保管,其安全性是通信安危的關鍵。例如 OpenSSH 客戶端默認會拒絕用權限開放的私鑰連接服務器,會出現如下提示:

# 放開私鑰權限

chmod 644 ~/.ssh/id_ras

# 連接服務器

ssh server

# openssh 客戶端出現如下報錯:

Permissions 0644 for '/home/tlanyan/.ssh/id_rsa' are too open.

It is required that your private key files are NOT accessible by others.

This private key will be ignored.

Load key "/home/tlanyan/.ssh/id_rsa": bad permissions

Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

私鑰和公鑰的作用一般分為兩種:

  • 公鑰加密,私鑰解密,主要用於通信;
  • 私鑰加密(簽名),公鑰解密(驗證),主要用於數字簽名。

本次做支付對接時,對其算法疑慮的地方是需要用到私鑰,按理要用對方的公鑰加密才對啊!後來意識到是用作數據簽名,用客戶端的私鑰是正確的。

理論上有了公鑰和密鑰,雙方就可以安全無礙的通信,那常說的證書是怎麼回事?

證書,顧名思義,就是證明的文件。例如瀏覽器和 tlanyan.me 服務器通信,瀏覽器怎麼知道對方就是 tlanyan.me 對應的服務器呢? 在不可信的網絡下通信,中立的第三方作用就顯現出來了。權威的第三方中立機構( Certificate Authority, CA)收到 tlanyan.me 持有者的證書請求並核驗信息後,將持有者的名稱、公鑰 與 CA 用 私鑰生成的數字簽名 等信息寫成證書頒發給申請者。

用戶與服務器通信時,服務器收到請求後將證書發給瀏覽器,瀏覽器對證書進行檢查(是否過期,能否用 CA 的公鑰驗證簽名等),並向第三方詢問是否為真(是否被吊銷等),確認無誤後,就可以放心地通信了。

證書包含公鑰,所以拿到證書意味著就拿到了對方的公鑰。幾乎所有的瀏覽器都會對證書進行校驗,以確保網頁通信中的安全。使用自簽發的證書,或者過期、與請求主機不符合的證書,都會導致瀏覽器發出安全警告,提醒用戶潛在的風險,如下圖所示:

非對稱加密與安全證書看這一篇就懂了

CURL 等第三方庫一般不會對證書進行檢查,那麼與服務器交互時如何確保通信的對方是真李逵而非李鬼?

答案是客戶端預先存一份服務器證書(證書從官網、對方郵件等可信渠道獲取),通信時校驗服務端發來的證書與本地預存的是否一致。如果不一致,則說明遇到了中間人攻擊,或預設的通信方實體已經變更,客戶端應對這種情況進行處理,例如打印警告或中斷通信。

而在校驗一致的情形下,客戶端用證書的公鑰加密信息發往服務端,如果對方是中間人,其沒有通信方的私鑰就無法解密信息,也會造成通信失敗。所以在私鑰不洩露的前提下,內置對方證書是解決中間人攻擊的最有效辦法,因為 CA 也有可能作假(參考 CNNIC),而瀏覽器需要與成千上萬個網站通信,不可能所有站點證書都內置,所以使用 CA 比較合理。之前做微信支付的對接,不理解微信服務器證書的作用,後來才理解其深意。

許多國外網站使用 HTTPS,照樣倒在國內偉大的防火牆之下。根據 HTTPS 加密通信的特點,同時 CA 加持,原則上牆是不可能知道通信的內容。那麼在 HTTPS 通信時,牆是怎麼識別出來並阻斷的?個人認為有三個可切入的點:

  • DNS 汙染,返回錯誤的 IP 地址;
  • 直接把域名的所有 IP 封掉;
  • 根據 HTTPS 的交互流程,客戶端和服務器協商密鑰階段的數據均為明文,獲取密鑰後才會加密數據(包括 URL)。協商階段的證書必然出現網站主機名,防火牆在這個階段可識別並阻斷。

以上想法出自個人猜測。

總結:通信的私鑰應該總是被妥善保管,在不可靠的網絡環境下通信,證書能避免中間人攻擊。

CSR、PEM、keystore 等

蘋果開發會接觸到 CSR、證書,安卓開發會用到 keystore,web 開發會用到 PEM、密鑰、證書、jks 等。這些都是什麼?

CSR(Certificate Sign Request)、公鑰、密鑰和證書歸屬為一類。CSR 用來獲取證書,包含申請人的公鑰、郵件等證明身份的信息。證書頒發機構(可以是自己)收到 CSR 後簽發證書,生成的證書中包含公鑰、有效期、持有人等信息。私鑰可單獨生成,也可在生成 CSR 的同時生成。整個過程中,私鑰應當都要被妥善保管,不能洩露。

keystore、PEM、cer/crt、key 等文件存儲格式可歸為一類。Java KeyStore(文件後綴 .keystore 或 .jks)是 Java 常用的存儲密鑰和證書的文件格式,需要設置文件密碼、別名和別名密碼,安卓打包和部署 Tomcat 時會用到;PEM(Privacy Enhanced Mail)以文本形式存放私鑰和證書(鏈);cer/crt 和 key 分別用來存放證書和密鑰;另外一種常見的格式是 pfx 和 p12,同 jks 格式,這類文件一般是二進制,訪問需要密碼。

PKI(Public key infrastructure)體系構建在公鑰加密基礎之上,主要解決證書的頒發和管理問題。證書管理中應用廣泛的兩個標準是 X509 和 PKCS。遵循 X509 標準的證書文件結尾多為 PEM、der、crt 等;遵循 PKCS 標準的證書常用後綴名是 pfx、p12 等。

本次對接暈乎的第二個地方是一處地方讀取密鑰需要密碼,另一處直接讀取。根據存儲格式可知原因:訪問遵循 PKCS#12 標準的 pfx 文件需要密碼,遵循 X509 規範的 PEM 文件則可直接查看內容。

OpenSSL

OpenSSL 是通用的加密庫,openssl 是基於它的命令行工具,上文提到的內容基本都在其功能範圍內。另一個與 openssl 類似的工具是 GPG(GNU Privacy Guard),區別是 OpenSSL 遵循 X509 標準,GPG 遵循 OpenPGP 標準。兩者加密的文件在格式上有所差異,無法解開對方加密過的文件。OpenSSL 和 GPG 內置在大多數 *nix 系統中,可直接使用。

以下示例基於 OpenSSL,GPG 的用法可查看文中最後的參考文獻。

openssl 命令的 man 頁面描述了其能力範圍:

The openssl program is a command line tool for using the various cryptography functions of

OpenSSL's crypto library from the shell. It can be used for

o Creation and management of private keys, public keys and parameters

o Public key cryptographic operations

o Creation of X.509 certificates, CSRs and CRLs

o Calculation of Message Digests

o Encryption and Decryption with Ciphers

o SSL/TLS Client and Server Tests

o Handling of S/MIME signed or encrypted mail

o Time Stamp requests, generation and verification

接下來看一些簡單的 openssl 使用示例:

md5:

echo tlanyan | openssl md5

## 結果與下條命令相同

echo tlanyan | md5sum

aes 加解密:

# 用法

# openssl aes-128-cbc -e -in 加密文件 -out 解密文件 -pass pass:密碼

# 例如

echo tlanyan > input

openssl aes-128-cbc -e -in input -out output -pass pass:1234567890abcdef

# 加密的內容在output中

# 解密

openssl aes-128-cbc -d -in output -o origin -pass pa:1234567890abcdef

生成 CSR、簽發證書:

# 先生成csr和私鑰

# 注意使用-nodes選項,否則私鑰會有密碼,用在nginx啟動時需要手動輸入

openssl req -new -out tlanyan.csr -newkey rsa:2048 -nodes -keyout tlanyan.priv.key

# 接下來的交互裡填入一些基本信息,完畢後會生成tlanyan.csr和tlanyan.priv.key兩個文件

# csr的格式如下:

# -----BEGIN CERTIFICATE REQUEST-----

# xxxx

# -----END CERTIFICATE REQUEST-----

# 密鑰文件的格式類似

# 有了csr,接下來為自己簽發證書

openssl req -x509 -sha256 -nodes -days 365 -in tlanyan.csr -key tlanyan.priv.key -out tlanyan.crt

# 命令結束後,目錄中出現tlanyan.crt的證書文件

# 校驗密鑰

openssl rsa -in tlanyan.priv.key --check

# 校驗csr

openssl req -in tlanyan.csr -verify

# 校驗證書

openssl x509 -in tlany.**crt -text -n**ooutPEM

轉換各種不同格式的證書:

# 將pem格式轉換成pfx/p12格式

openssl pkcs12 -export -out tlanyan.pfx -inkey tlanyan.priv.key -in tlaPEMn.crt

# 將pfx格式轉換成pem格式

openssl pkcs12 -in tlanyan.pfx -out tlanyan.cer -nodes

# 生成的tlanyan.cer文件包含了證書和公鑰,對應導入前的tlanyan.crt和tnPEM . pri v.key兩個文件

pem 和 jks 的格式轉換太過複雜, 具體請看 Oracle 的文檔。

以上演示的只是 openssl 工具包中的極小一部分命令。更多的用法請參考官方文檔。

總結

本文介紹了非對稱加密和證書的相關概念,並演示了 openssl 命令的一些基本用法,希望能夠幫助到對這方面內容有疑惑的讀者。文章涉及內容較多,理解上稍顯難度。另外本文參考了不少文章,理解上的不到之處敬請指正。

原文鏈接:my.oschina.net/editorial-story/blog/1837585 如有侵權請聯繫刪除

參考

  • https://coolshell.cn/articles/7425.html
  • http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO/x64.html
  • https://legacy.gitbook.com/book/yeasy/blockchain_guide/details
  • https://www.integralist.co.uk/posts/security-basics/
  • https://rakhesh.com/infrastructure/notes-on-cryptography-ciphers-rsa-dsa-aes-rc4-ecc-ecdsa-sha-and-so-on/
  • https://www.sslshopper.com/what-is-a-csr-certificate-signing-request.html
  • http://www.cnblogs.com/jeremy-blog/p/5291296.html
  • https://www.sslshopper.com/ssl-converter.html
  • https://docs.oracle.com/cd/E35976_01/server.740/es_admin/sPEMtadm_ssl_convert_pem_to_jks.html


分享到:


相關文章: