聊一聊,前端常見(jiàn)的加密算法
在信息安全越來(lái)越受重視的今天,前端的各種加密也變得更加重要。通常跟服務(wù)器的交互中,為保障數(shù)據(jù)傳輸?shù)陌踩?,避免被人抓包篡改?shù)據(jù),除了 https 的應(yīng)用,還需要對(duì)傳輸數(shù)據(jù)進(jìn)行加解密。
目前常見(jiàn)的加密算法可以分成三類
- 對(duì)稱加密算法:AES、…
- 非對(duì)稱加密算法:RSA、…
- Hash 算法:MD5、…
二、對(duì)稱加密算法
對(duì)稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。它要求發(fā)送方和接收方在安全通信之前,商定一個(gè)密鑰。對(duì)稱算法的安全性依賴于密鑰,泄漏密鑰就意味著任何人都可以對(duì)他們發(fā)送或接收的消息解密,所以密鑰的保密性對(duì)通信的安全性至關(guān)重要。
特點(diǎn)
- 優(yōu)點(diǎn):算法公開(kāi)、計(jì)算量小、加密速度快、加密效率高。
- 缺點(diǎn):在數(shù)據(jù)傳送前,發(fā)送方和接收方必須商定好密鑰,然后雙方保存好密鑰。如果一方的密鑰被泄露,那么加密信息也就不安全了
- 使用場(chǎng)景:本地?cái)?shù)據(jù)加密、https 通信、網(wǎng)絡(luò)傳輸?shù)?/li>
AES
AES:高級(jí)加密標(biāo)準(zhǔn)(Advanced Encryption Standard)為最常見(jiàn)的對(duì)稱加密算法(微信小程序加密傳輸就是用這個(gè)加密算法的)。
密鑰:用來(lái)加密明文的密碼。密鑰為接收方與發(fā)送方協(xié)商產(chǎn)生,但不可以直接在網(wǎng)絡(luò)上傳輸,否則會(huì)導(dǎo)致密鑰泄漏,通常是通過(guò)非對(duì)稱加密算法加密密鑰,然后再通過(guò)網(wǎng)絡(luò)傳輸給對(duì)方,或者直接面對(duì)面商量密鑰。密鑰是絕對(duì)不可以泄漏的,否則會(huì)被攻擊者還原密文,竊取數(shù)據(jù)。
在項(xiàng)目中需要用到 AES 加密時(shí),可以使用開(kāi)源的 js 庫(kù):crypto-js
- var CryptoJS = require('crypto-js');
- var data = { id: 1, text: 'Hello World' };
- // 加密生成密文
- var ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), 'secret_key_123').toString();
- // 解密得到明文
- var bytes = CryptoJS.AES.decrypt(ciphertext, 'secret_key_123');
- var decryptedData = JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
三、非對(duì)稱加密算法
非對(duì)稱加密算法需要兩個(gè)密鑰:公開(kāi)密鑰(publickey:簡(jiǎn)稱公鑰)和私有密鑰(privatekey:簡(jiǎn)稱私鑰)。公鑰與私鑰是一對(duì),如果用公鑰對(duì)數(shù)據(jù)進(jìn)行加密,只有用對(duì)應(yīng)的私鑰才能解密。因?yàn)榧用芎徒饷苁褂玫氖莾蓚€(gè)不同的密鑰,所以這種算法叫作非對(duì)稱加密算法。
特點(diǎn)
- 優(yōu)點(diǎn):非對(duì)稱加密與對(duì)稱加密相比其安全性更好
- 缺點(diǎn):加密和解密花費(fèi)時(shí)間長(zhǎng)、速度慢,只適合對(duì)少量數(shù)據(jù)進(jìn)行加密。
- 使用場(chǎng)景:https 會(huì)話前期、CA 數(shù)字證書(shū)、信息加密、登錄認(rèn)證等
RSA
RSA 加密算法是非對(duì)稱加密算法最常見(jiàn)的一種。RSA 是 1977 年由 Ron Rivest、Adi Shamir 和 Leonard Adleman 一起提出的。RSA 就是他們?nèi)诵帐祥_(kāi)頭字母拼在一起組成的。
在項(xiàng)目中需要用到 RSA 加密時(shí),可以使用開(kāi)源的 js 庫(kù):jsencrypt
- // 使用公鑰加密
- var publicKey = 'public_key_123';
- var encrypt = new JSEncrypt();
- encrypt.setPublicKey(publicKey);
- var encrypted = encrypt.encrypt('Hello World');
- // 使用私鑰解密
- var privateKey = 'private_key_123';
- var decrypt = new JSEncrypt();
- decrypt.setPrivateKey(privateKey);
- var uncrypted = decrypt.decrypt(encrypted);
四、Hash 算法
Hash,一般翻譯做“散列”,也有直接音譯為“哈希”的,就是把任意長(zhǎng)度的輸入(又叫做預(yù)映射, pre-image),通過(guò)散列算法,變換成固定長(zhǎng)度的輸出,該輸出就是散列值。這種轉(zhuǎn)換是一種壓縮映射,也就是,散列值的空間通常遠(yuǎn)小于輸入的空間,不同的輸入可能會(huì)散列成相同的輸出,而不可能從散列值來(lái)唯一的確定輸入值。
簡(jiǎn)單的說(shuō)就是一種將任意長(zhǎng)度的消息壓縮到某一固定長(zhǎng)度的消息摘要的函數(shù)。
特點(diǎn)
- 優(yōu)點(diǎn):不可逆、易計(jì)算、特征化
- 缺點(diǎn):可能存在散列沖突
- 使用場(chǎng)景:文件或字符串一致性校驗(yàn)、數(shù)字簽名、鑒權(quán)協(xié)議
MD5
MD5 是比較常見(jiàn)的 Hash 算法,對(duì)于 MD5 而言,有兩個(gè)特性是很重要的,第一:明文數(shù)據(jù)經(jīng)過(guò)散列以后的值是定長(zhǎng)的;第二:是任意一段明文數(shù)據(jù),經(jīng)過(guò)散列以后,其結(jié)果必須永遠(yuǎn)是不變的。前者的意思是可能存在有兩段明文散列以后得到相同的結(jié)果,后者的意思是如果我們散列特定的數(shù)據(jù),得到的結(jié)果一定是相同的。
比如在登錄時(shí)將密碼進(jìn)行 md5 加密再傳輸給服務(wù)器,服務(wù)器中的密碼也是用 md5 加密后存儲(chǔ)的,那么只要驗(yàn)證加密后的密文是否一致則可。
在項(xiàng)目中需要用到 MD5 加密時(shí),可以使用開(kāi)源的 js 庫(kù):JavaScript-MD5
- var hash = md5('Hello World');
- // b10a8db164e0754105b7a99be72e3fe5
五、Base64 編碼
Base64 編碼只是一種編碼格式并不是加密算法,它可用于在 HTTP 環(huán)境下傳遞較長(zhǎng)的標(biāo)識(shí)信息。
特點(diǎn)
- 可以將任意的二進(jìn)制數(shù)據(jù)進(jìn)行 Base64 編碼
- 數(shù)據(jù)加密之后,數(shù)據(jù)量會(huì)變大,變大 1/3 左右
- 編碼后有個(gè)非常顯著的特點(diǎn),末尾有個(gè)=號(hào)
- 可進(jìn)行反向解碼
- Base64 編碼具有不可讀性
現(xiàn)代瀏覽器都提供了 Base64 編碼、解碼方法,btoa() 和 atob()
- var enc = window.btoa('Hello World');
- // SGVsbG8gV29ybGQ=
- var str = window.atob(enc);
- // Hello World
六、總結(jié)
在業(yè)務(wù) http 請(qǐng)求中,AES 的密鑰在前端隨機(jī)生成,從服務(wù)器獲取 RSA 的公鑰,對(duì) AES 的密鑰進(jìn)行非對(duì)稱加密,把加密后的密鑰在請(qǐng)求頭中傳給服務(wù)器,用 AES 對(duì) body 進(jìn)行加密。服務(wù)器收到請(qǐng)求頭中的加密后的密鑰,用 RSA 的密鑰進(jìn)行解密,得到明文的 AES 密鑰,即可對(duì) body 進(jìn)行解密。md5 有校驗(yàn)字符串一致性的特性,為避免請(qǐng)求被攔截后篡改 body,可在發(fā)請(qǐng)求時(shí),將 body 字符串進(jìn)行一個(gè) md5 加密后在請(qǐng)求頭傳輸,服務(wù)器收到請(qǐng)求后,解密 body 后再 md5 與請(qǐng)求頭的進(jìn)行校驗(yàn),可驗(yàn)證是否請(qǐng)求被篡改。