前幾日做支付對接時呼奢,被對方文檔中的加密方式搞暈乎了一會。意識到證書加密方面的理解不夠深入切平,事后查閱參考資料補習一波握础。本文是根據(jù)期間的學習,以及長期以來的實踐做出的總結(jié)悴品。
加密方式
密碼學是涉及數(shù)學禀综、電子信息、計算機等多學科的一門重要學科苔严,是現(xiàn)代互聯(lián)網(wǎng)安全的基石定枷,也是目前如火如荼的區(qū)塊鏈技術的安全保障。概括來說邦蜜,加密方式可歸結(jié)為不可逆加密與可逆加密依鸥。
不可逆加密
信息摘要(Message Digest)和安全散列(Secure Hash)算法屬于此類,常見的算法包括 MD5悼沈、SHA1贱迟、PBKDF2、bcrypt 等絮供。此類算法可將任意大小的原始數(shù)據(jù)變換成規(guī)定長度的輸出衣吠,即獲取內(nèi)容的數(shù)字指紋,常用于校驗原始內(nèi)容是否被篡改壤靶。這類算法的主要特點是:
不可逆性缚俏。除非窮舉等手段,原則上不存在根據(jù)密文推斷出原文的算法贮乳;
雪崩效應忧换。對輸入數(shù)據(jù)敏感,原始內(nèi)容的極小改動會造成輸出的大差異向拆;
防碰撞性亚茬。原則上很難找到兩組不同的原文,經(jīng)過加密后密文相同浓恳。
左耳朵耗子的“RSYNC 的核心算法”介紹了 MD5 算法在 rsync 中的具體應用刹缝。MD5 和 SHA1 已經(jīng)被證實不安全(王小云教授在04年找到 MD5 迅速碰撞方法,谷歌在17年完成了 SHA1 的第一次碰撞)颈将,實踐中建議至少用 SHA-256 算法梢夯,或采用對算力不敏感的 scrypt、Argon2 等算法晴圾。
哈希算法(安全散列)的一個變種是 HMAC(Hash-based Message Authentication Code)算法颂砸,用于解決身份認證和防抵賴。HMAC 算法的輸入為一個密鑰(通信雙方共享)、一種哈希算法(常為經(jīng)典哈希算法)和原始數(shù)據(jù)人乓,輸出的內(nèi)容格式取決于所采用的哈希算法梗醇。由于只有通信雙方知曉密鑰,所以可確認信息就是由對方發(fā)出撒蟀。
可逆加密
哈希算法可保證通信中的數(shù)據(jù)不被篡改叙谨,而可逆加密算法是還原出明文的關鍵”M停可逆加密算法可分成三類:
基于算法的加密算法手负,也被稱為古典加密算法,如 HTTP 認證中的 base64姑尺,比特幣生成地址用的 base58(公開的算法也可稱作編碼方式)竟终。這類算法主要對原始內(nèi)容進行置換和替換得到密文,安全性依賴于算法是否外泄切蟋;
對稱加密算法统捶,加密和解密使用同一個密鑰。對稱加密算法的出現(xiàn)標志密碼學進入現(xiàn)代密碼學階段柄粹,密文的安全性從依賴于算法轉(zhuǎn)向依賴于密鑰喘鸟。常見的對稱加密算法有 DES、3DES驻右、AES什黑;
非對稱加密算法,加密和解密使用不同的密鑰堪夭。非對稱加密算法開創(chuàng)了密碼學的里程碑愕把,解決了對稱加密過程中密鑰分發(fā)的安全問題,被認為現(xiàn)代密碼學最偉大的發(fā)明森爽。常見的算法有 RSA恨豁、DH(Diffie-Hellman)、橢圓曲線算法(Elliptic curve cryptography爬迟,ECC)橘蜜。
非對稱算法設計巧妙,但實際中要結(jié)合對稱加密使用雕旨。原因是某些算法不能加解密(DH扮匠、DSA)捧请,或者效率太低(RSA)凡涩,或者能處理的數(shù)據(jù)大小有限制(RSA)。而對稱加密算法的有點是速度快疹蛉、加密強度高活箕。常用非對稱算法獲得共享密鑰,之后用對稱加密處理數(shù)據(jù)可款。本文的重點是非對稱加密及其衍生概念育韩,下面逐一介紹。
公鑰、私鑰和證書
除算法外维雇,非對稱加密中另外兩個重要的概念是公鑰和私鑰派任。公鑰對外公開,任何人均可持有和使用悉罕;私鑰自行保管赤屋,其安全性是通信安危的關鍵。例如 OpenSSH 客戶端默認會拒絕用權(quán)限開放的私鑰連接服務器壁袄,會出現(xiàn)如下提示:
# 放開私鑰權(quán)限chmod644~/.ssh/id_ras# 連接服務器ssh server# openssh 客戶端出現(xiàn)如下報錯:Permissions0644for'/home/tlanyan/.ssh/id_rsa'are too open.Itisrequired that yourprivatekey files are NOT accessiblebyothers.Thisprivatekey will be ignored.Load key"/home/tlanyan/.ssh/id_rsa":bad permissionsPermissiondenied(publickey,gssapi-keyex,gssapi-with-mic).
私鑰和公鑰的作用一般分為兩種:
公鑰加密类早,私鑰解密,主要用于通信嗜逻;
私鑰加密(簽名)涩僻,公鑰解密(驗證),主要用于數(shù)字簽名栈顷。
本次做支付對接時逆日,對其算法疑慮的地方是需要用到私鑰,按理要用對方的公鑰加密才對疤逊铩屏富!后來意識到是用作數(shù)據(jù)簽名,用客戶端的私鑰是正確的蛙卤。
理論上有了公鑰和密鑰狠半,雙方就可以安全無礙的通信,那常說的證書是怎么回事颤难?
證書神年,顧名思義,就是證明的文件行嗤。例如瀏覽器和 tlanyan.me 服務器通信已日,瀏覽器怎么知道對方就是 tlanyan.me 對應的服務器呢??在不可信的網(wǎng)絡下通信栅屏,中立的第三方作用就顯現(xiàn)出來了飘千。權(quán)威的第三方中立機構(gòu)( Certificate Authority, CA)收到 tlanyan.me 持有者的證書請求并核驗信息后,將持有者的名稱栈雳、公鑰?與 CA 用?私鑰生成的數(shù)字簽名?等信息寫成證書頒發(fā)給申請者护奈。
用戶與服務器通信時,服務器收到請求后將證書發(fā)給瀏覽器哥纫,瀏覽器對證書進行檢查(是否過期霉旗,能否用CA?的公鑰驗證簽名等),并向第三方詢問是否為真(是否被吊銷等),確認無誤后厌秒,就可以放心地通信了读拆。下面是我的一個私人交流群對 Java技術,架構(gòu)技術 感興趣的同學鸵闪,歡迎加 QQ群:874811168 檐晕,一起學習,相互討論蚌讼。群內(nèi)已經(jīng)將知識體系整理好棉姐,作為大家的一個福利 大家都可以加群免費的獲取。
證書包含公鑰啦逆,所以拿到證書意味著就拿到了對方的公鑰伞矩。幾乎所有的瀏覽器都會對證書進行校驗,以確保網(wǎng)頁通信中的安全夏志。使用自簽發(fā)的證書乃坤,或者過期、與請求主機不符合的證書沟蔑,都會導致瀏覽器發(fā)出安全警告湿诊,提醒用戶潛在的風險,如下圖所示:
CURL 等第三方庫一般不會對證書進行檢查瘦材,那么與服務器交互時如何確保通信的對方是真李逵而非李鬼厅须?
答案是客戶端預先存一份服務器證書(證書從官網(wǎng)、對方郵件等可信渠道獲仁匙亍)朗和,通信時校驗服務端發(fā)來的證書與本地預存的是否一致。如果不一致簿晓,則說明遇到了中間人攻擊眶拉,或預設的通信方實體已經(jīng)變更,客戶端應對這種情況進行處理憔儿,例如打印警告或中斷通信忆植。
而在校驗一致的情形下,客戶端用證書的公鑰加密信息發(fā)往服務端谒臼,如果對方是中間人朝刊,其沒有通信方的私鑰就無法解密信息,也會造成通信失敗蜈缤。所以在私鑰不泄露的前提下拾氓,內(nèi)置對方證書是解決中間人攻擊的最有效辦法,因為 CA 也有可能作假(參考 CNNIC)劫樟,而瀏覽器需要與成千上萬個網(wǎng)站通信痪枫,不可能所有站點證書都內(nèi)置,所以使用 CA 比較合理叠艳。之前做微信支付的對接奶陈,不理解微信服務器證書的作用,后來才理解其深意附较。
許多國外網(wǎng)站使用 HTTPS吃粒,照樣倒在國內(nèi)偉大的防火墻之下。根據(jù) HTTPS 加密通信的特點拒课,同時 CA 加持徐勃,原則上墻是不可能知道通信的內(nèi)容。那么在 HTTPS 通信時早像,墻是怎么識別出來并阻斷的僻肖?個人認為有三個可切入的點:
DNS 污染,返回錯誤的 IP 地址卢鹦;
直接把域名的所有 IP 封掉臀脏;
根據(jù) HTTPS 的交互流程,客戶端和服務器協(xié)商密鑰階段的數(shù)據(jù)均為明文冀自,獲取密鑰后才會加密數(shù)據(jù)(包括 URL)揉稚。協(xié)商階段的證書必然出現(xiàn)網(wǎng)站主機名,防火墻在這個階段可識別并阻斷熬粗。
以上想法出自個人猜測搀玖。
總結(jié):通信的私鑰應該總是被妥善保管,在不可靠的網(wǎng)絡環(huán)境下通信驻呐,證書能避免中間人攻擊灌诅。
CSR、PEM含末、keystore 等
蘋果開發(fā)會接觸到 CSR延塑、證書,安卓開發(fā)會用到 keystore答渔,web 開發(fā)會用到 PEM关带、密鑰、證書沼撕、jks 等宋雏。這些都是什么?
CSR(Certificate Sign Request)务豺、公鑰磨总、密鑰和證書歸屬為一類。CSR 用來獲取證書笼沥,包含申請人的公鑰蚪燕、郵件等證明身份的信息娶牌。證書頒發(fā)機構(gòu)(可以是自己)收到 CSR 后簽發(fā)證書,生成的證書中包含公鑰馆纳、有效期诗良、持有人等信息。私鑰可單獨生成鲁驶,也可在生成 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)體系構(gòu)建在公鑰加密基礎之上遇绞,主要解決證書的頒發(fā)和管理問題。證書管理中應用廣泛的兩個標準是 X509 和 PKCS燎窘。遵循 X509 標準的證書文件結(jié)尾多為 PEM摹闽、der、crt 等褐健;遵循 PKCS 標準的證書常用后綴名是 pfx付鹿、p12 等。
本次對接暈乎的第二個地方是一處地方讀取密鑰需要密碼蚜迅,另一處直接讀取舵匾。根據(jù)存儲格式可知原因:訪問遵循 PKCS#12 標準的 pfx 文件需要密碼,遵循 X509 規(guī)范的 PEM 文件則可直接查看內(nèi)容谁不。
OpenSSL
OpenSSL 是通用的加密庫坐梯,openssl 是基于它的命令行工具,上文提到的內(nèi)容基本都在其功能范圍內(nèi)刹帕。另一個與 openssl 類似的工具是 GPG(GNU Privacy Guard)吵血,區(qū)別是 OpenSSL 遵循 X509 標準谎替,GPG 遵循 OpenPGP 標準。兩者加密的文件在格式上有所差異蹋辅,無法解開對方加密過的文件钱贯。OpenSSL 和 GPG 內(nèi)置在大多數(shù) *nix 系統(tǒng)中,可直接使用晕翠。
以下示例基于 OpenSSL喷舀,GPG 的用法可查看文中最后的參考文獻砍濒。
openssl 命令的 man 頁面描述了其能力范圍:
The openssl program is a command line toolforusingthe various cryptography functions ofOpenSSL's crypto library from the shell. It can be usedforo? Creationandmanagement ofprivatekeys,publickeysandparameterso? Public key cryptographic operationso? Creation of X.509certificates, CSRsandCRLso? Calculation of Message Digestso? EncryptionandDecryption with Cipherso? SSL/TLS ClientandServer Testso? Handling of S/MIMEsignedorencrypted mailo? Time Stamp requests, generationandverification
接下來看一些簡單的 openssl 使用示例:
md5:
echotlanyan | openssl md5## 結(jié)果與下條命令相同echotlanyan | md5sum
aes 加解密:
# 用法#openssl aes-128-cbc -e -in加密文件 -out 解密文件 -pass pass:密碼# 例如echo tlanyan > inputopenssl aes-128-cbc -e -in input -out output -pass pass:1234567890abcdef# 加密的內(nèi)容在output中# 解密openssl aes-128-cbc -d -in output -o origin -pass pa:1234567890abcdef
生成 CSR淋肾、簽發(fā)證書:
# 先生成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,接下來為自己簽發(fā)證書openssl req -x509 -sha256 -nodes -days 365 -in tlanyan.csr -key tlanyan.priv.key -out tlanyan.crt# 命令結(jié)束后杠河,目錄中出現(xiàn)tlanyan.crt的證書文件# 校驗密鑰openssl rsa -in tlanyan.priv.key --check# 校驗csropenssl req -in tlanyan.csr -verify# 校驗證書openssl x509 -in tlany.**crt -text -n**ooutPEM? ? 下面是我的一個私人交流群對 Java技術碌尔,架構(gòu)技術 感興趣的同學,歡迎加 QQ群:874811168 券敌,一起學習唾戚,相互討論。群內(nèi)已經(jīng)將知識體系整理好待诅,作為大家的一個福利 大家都可以加群免費的獲取叹坦。
轉(zhuǎn)換各種不同格式的證書:
# 將pem格式轉(zhuǎn)換成pfx/p12格式openssl pkcs12 -export-outtlanyan.pfx -inkey tlanyan.priv.key -intlaPEMn.crt# 將pfx格式轉(zhuǎn)換成pem格式openssl pkcs12 -intlanyan.pfx -outtlanyan.cer -nodes# 生成的tlanyan.cer文件包含了證書和公鑰,對應導入前的tlanyan.crt和tnPEM . pri v.key兩個文件
pem 和 jks 的格式轉(zhuǎn)換太過復雜卑雁, 具體請看 Oracle 的文檔募书。
以上演示的只是 openssl 工具包中的極小一部分命令。更多的用法請參考官方文檔测蹲。
感謝閱讀莹捡!