瀏覽器端加密難題及解決方案
在創(chuàng)建 Opal 網(wǎng)站時(shí),我們所面臨的挑戰(zhàn),是尋找在瀏覽器中加密解密的可靠方法。這篇文章描述了瀏覽器端加密所面臨的難題,并指出了近期的科技進(jìn)步所提供的一種解決方案。
在 Web 應(yīng)用中加密的三種選擇
只有 JavaScript 才是所有瀏覽器都支持的語言。與 Opal 同類的 Web 應(yīng)用使用 JavaScript 編寫,以便于在任何現(xiàn)代瀏覽器上運(yùn)作。如果這些應(yīng)用要使用加密函數(shù),那么 JavaScript 必須能夠訪問到它們。
目前,要把加密函數(shù)暴露給瀏覽器的 JavaScript,只有三個(gè)選項(xiàng):
1、使用插件加密
插件是指運(yùn)行在瀏覽器中,可以由 JavaScript 調(diào)用的,編譯過的代碼。
比如,Java 和 Flash 中存在的加密庫。這樣的做法通常性能很高,但是需要用戶安裝瀏覽器插件程序,而這,也是人們不愿意,或者完成不了的部分(如果他們使用的是公用電腦)。
另外一個(gè)選項(xiàng)是使用 Chrome 瀏覽器的 NaCl 客戶端(Native Client) 程序,它允許運(yùn)行由 C 或者 C++ 編譯出的機(jī)器代碼。同樣,這種做法的性能很高,但是NaCl客戶端程序只能用于 Chrome 瀏覽器。
即使這些插件和NaCl客戶端程序在速度上有優(yōu)勢(shì),但是因?yàn)樗麄冃枰脩羰褂锰厥獠寮?,或者使用特定瀏覽器,因此這種做法的可移植性不是很好。
2、使用 Web 加密 API
即將出現(xiàn)的 Web 加密 API 會(huì)給 JavaScript 提供原生的基本加密接口,讓 Web 應(yīng)用可以更快地加密解密。但是,這項(xiàng)接口仍在草案階段,主流瀏覽器要采用這項(xiàng)技術(shù)還很長(zhǎng)的一段時(shí)間。而現(xiàn)在,能在多數(shù)瀏覽器中使用的,只有crypto.getRandomValues()函數(shù)。
在 Web 加密 API 廣泛應(yīng)用之前,這并不是一項(xiàng)切實(shí)可行的瀏覽器端加密方案。
3、直接用 JavaScript 加密
這種方案的優(yōu)點(diǎn)就在于高度的可移植性。所有的瀏覽器都可以執(zhí)行 JavaScript,也就意味著所有的瀏覽器都可以調(diào)用 JavaScript 寫成的加密庫。
在 JavaScript 中加密主要有兩項(xiàng)缺陷:安全性和速度。我們會(huì)輪流談到這兩項(xiàng)缺陷。
JavaScript 加密可以變得安全
有文章聲稱“JavaScript 加密是有害的”,并且列出了許多證據(jù)支持這一論述。
文中的某些觀點(diǎn)現(xiàn)在不再準(zhǔn)確了。例如,這篇文章說,Math.random()函數(shù)不是隨機(jī)數(shù)的良好來源,所以不可能得到足夠的隨機(jī)數(shù)用來加密。 Math.random() 函數(shù)的確不是隨機(jī)數(shù)的良好來源。在現(xiàn)代瀏覽器已經(jīng)提供了 crypto.getRandomValues()函數(shù)以取得足夠數(shù)量的隨機(jī)數(shù)。
這個(gè)帖子中有相當(dāng)多的案例證明 JavaScript 加密是個(gè)壞主意,但這種做法也它的意義。
這條回答有 利地駁斥了***個(gè)帖子中的許多觀點(diǎn),同時(shí)也指出了 JavaScript 加密的兩個(gè)有效用例:端對(duì)端的信息加密(也就是對(duì)主機(jī)訪問做出防護(hù)的應(yīng)用)以及安全的遠(yuǎn)程密碼認(rèn)證。這些正好是 Opal 加密的使用場(chǎng)景,所以我們使用 JavaScript 加密是非常自然的。
JavaScript 加密可以很快
直到最近,JavaScript 在進(jìn)行安全加密所要用到的復(fù)雜計(jì)算時(shí)都很慢。這直接導(dǎo)致了許多應(yīng)用程序需要依賴于插件所提供的加密功能,這樣的做法可移植性差,同時(shí)也會(huì)讓用戶厭煩。
幸運(yùn)的是,JavaScript 近年來的性能有極大提升,所以完全使用 JavaScript 進(jìn)行加密操作是可行的?,F(xiàn)在有許多 JavaScript 加密庫可供選擇(鏈接1,鏈接2,鏈接3,鏈接4,鏈接5,鏈接6,鏈接7,鏈接8,鏈接9)。
于是就變成了選哪一個(gè)庫的問題。
NaCl,一個(gè)可以信賴的 C 語言加密庫
NaCl (讀作 “salt”) 是一個(gè) C 語言的庫,提供對(duì)稱式密鑰加密解密和公鑰簽名認(rèn)證的應(yīng)用函數(shù)。它由密碼學(xué)人士編寫,在加密社區(qū)廣為人知,受到信賴。問題之一是 NaCl 是 C 語言,而不是 JavaScript 編寫的。
js-NaCl:將 NaCl 編譯成 JavaScript
幸運(yùn)的是,我們能把 NaCl 編譯成 LLVM 的字節(jié)碼,然后用 emscripten 將這些字節(jié)碼編譯成 JavaScript。并且,LLVM 編譯器能在編譯時(shí)作許多優(yōu)化,所以得到的 JavaScript 代碼也會(huì)得到優(yōu)化。因此我們可以將 NaCl 庫編譯成 JavaScript,作好在瀏覽器中運(yùn)行的準(zhǔn)備!
js-nacl 項(xiàng)目正是: 編譯成 JavaScript 的 NaCl 加密庫。
asm.js 的速度很快!
更好的是,emscripten 編譯出的代碼是 JavaScript 的子集,也叫做asm.js。你可以將 asm.js 當(dāng)作很像 JavaScript 的匯編語言。瀏覽器遇到了 asm.js 的代碼塊時(shí),會(huì)將其編譯成高效的機(jī)器碼,運(yùn)行速度接近原生代碼。
目前主要只有 Firefox 瀏覽器支持 asm.js 的優(yōu)化。這就使 js-nacl 在 Firefox 中的加密解密非常迅速,視具體操作的不同,比 Chrome 瀏覽器的速度快 2 至 8 倍。但是即使是 Chrome,js-nacl 也很快,超過了我們所測(cè)試的其他所有加密庫。
NaCl 這樣備受信賴的加密庫和現(xiàn)代瀏覽器的快速執(zhí)行,使像 Opal 這樣的 Web 應(yīng)用都應(yīng)當(dāng)使用 js-nacl 庫。
同樣的原因下,Opal 使用了由 emscripten 編譯出的 asm.js 版 scrypt 庫來擴(kuò)展密鑰(正在這篇文章中啟用)。你可以看到由項(xiàng)目維護(hù)者提供的 js-nacl 和 js-scrypt 性能的對(duì)比。我們同時(shí)也給 js-nacl 作了jsperf 測(cè)試,以了解各個(gè)不同瀏覽器版本的性能差異,你也可以隨意嘗試。