前端該知道些密碼學和安全上的事兒
今年至少有六個月的時間在和密碼學,安全,隱私上的事情打交道,很有必要為今年總結一篇收官之作,整篇文章會描述一些基礎概念,以及我力所能及的一些理解,這份知識很有可能不準確,主要讓前端的同學們有一些概念,知道有這么回事,大佬輕拍;
密碼學淺識
在密碼學的世界里加密之前的消息被稱為明文 plaintext,加密之后的消息被稱為密文ciphertext,如果一段密文需要被解密再閱讀,這個過程被稱之為 decrypt,反之一段plaintext 需要被加密,這個過程被稱之為 encrypt。那么在處理這些問題的過程(解決加密/解密的步驟)通常被稱之為 算法,加密算法和解密算法被組合起來叫 密碼算法。
目前我個人所接觸到的主要是:
- 對稱密碼
- 單向散列函數
- 非對稱密碼
- Web Crypto API
其中對于公鑰證書的數字簽名等等。別著急,這些概念性的內容可能會非常的枯燥,因此我并不會描述很多,反而從實際性的問題出發,舉例在前端的領域中,上述三個方向上著重解決什么問題。
- https://code.google.com/archive/p/crypto-js/
- https://github.com/brix/crypto-js
- https://github.com/PeculiarVentures/PKI.js
- https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Crypto_API
對稱密碼
比較典型的如 AES ,它是指在加密和解密的過程中使用同一個 密鑰 的處理這個過程。我們知道,目前在中國大陸的Web世界中(不僅是Web也包括App),二維碼的流行程度幾乎很多場景里都有使用,這種不經過網絡的直接獲取數據,非常適合使用這種對稱加密/解密的方式來傳輸數據,前端這邊會使用 crypto-js 來處理 AES,這個 Google 開源的庫支持 AES-128,AES-192,AES-256:
- import * as CryptoJS from "crypto-js";
- export function aesDecrypt(text, originKey){
- const bytes = CryptoJS.AES.decrypt(text, originKey);
- return bytes.toString(CryptoJS.enc.Utf8);
- }
- export function aesEncrypt(text, originKey){
- const c = CryptoJS.AES.encrypt(text, originKey);
- return c.toString();
- }
單向散列函數
這個函數如果要舉例的話比較典型的有我們下載任何軟件包時同時會校驗一下MD5值來防止下載的軟件包是一個被篡改的軟件包。單向散列函數就是為了計算散列值而準備的函數,crypto-js包中不僅提供了 md5,hmac 也有 sha256 。如果有一天前端和服務端約定要對數據進行校驗,當然最簡單的方式是 md5 ,但這已經是一種不安全的計算了,最好使用 sha256:
- import * as CryptoJS from "crypto-js";
- const sha256 = CryptoJS.algo.SHA256.create();
- sha256.update("Message Part 1");
- sha256.update("Message Part 2");
- sha256.update("Message Part 3");
- const hash = sha256.finalize();
非對稱密碼
密碼學的那本書里講了很多密鑰分配的問題,這種思考確實...很燒腦,不過這種前輩經歷過的思考,在我們的實際應用中其實會有一個很有趣的過程。非對稱密碼,就是將密鑰分了兩個部分:加密密鑰和解密密鑰,發送者使用加密密鑰對消息進行加密,接收者使用解密密鑰進行解密。在這里加密密鑰是可以被公開的,只有解密密鑰是絕對不能被公開的。那么這其中使用了什么樣的算法來生成密鑰對(說實話,我也不是很清楚,因為沒看懂),但前端的同學們了解到非對稱密碼還是很有必要。對于加密密鑰它被稱之為 `public key`,對應的解密密鑰被稱之為 `private key`,目前被廣泛使用的公鑰密碼算法叫做 `RSA`。
除了加密之外,非對稱密碼還可以解決身份認證的問題,想一想如果有人偽裝了一個和你一樣的微信,同樣的頭像和昵稱,同樣的說話語氣,詐騙集團極有可能因此從你處獲取到真正的經濟利益。因為非對稱密碼的公鑰是可以公開的,一個人對應一個公鑰,在密碼的世界里,根本無法偽裝,因為無法解密也無法得到認證。
我想如果你會寫 Web 版的區塊鏈錢包或者錢包,非對稱密碼的使用頻率還是相當高的,除此之外它所在的場景會特別的特殊(前端而言),不過如果在其他的領域,會比較常見。
Web Crypto API
Web Crypto API 為腳本提供加密了一套關于密碼(學)的接口,以便用于構建需要使用密碼的系統。這套API的基礎特性是允許在腳本中使用和維護密鑰的存儲,但是不允許使用JavaScript訪問這些密鑰本身。
Web Crypto API 必須在 HTTPS 網頁中才能被使用(Chrome)
這套接口允許腳本使用以下功能:
- digest, 摘要,即計算數據塊hash的能力,用于檢測數據的變動。
- mac, 計算消息驗證碼的能力。
- sign and verify, 對文檔進行數字簽名和驗證的能力。
- encrypt and decrypt, 對文檔進行加密和解密的能力。
- import and export, 導入和導出密鑰的能力。
- key generation, 產生密碼學中使用的私鑰或者密鑰對的能力,不使用base key,而是使用本地系統的能力。(the ability to create a cryptographically secure key, or key pair, without the use of base key, but using the available entropy of the local system.)
- key wrapping and unwrapping, 密鑰包裹和解包,即在不接觸底層密鑰內容的情況下,與第三方傳送、接收使用另一個密鑰加密后的密鑰的能力。
- random, 生成密碼學中使用的偽隨機數的能力。
使用 Web Crypto API 的原因是我所使用的 PKI.js 依賴了 Web Crypto API 。
PKI(Public Key Infrastructure)是一個用非對稱密碼算法原理和技術來實現并提供安全服務的具有通用性的安全基礎設施,是一種遵循標準的利用公鑰加密技術為網上電子商務、電子政務的開展,提供一整套安全的基礎平臺。PKI,公鑰基礎設施,顧名思義,PKI技術就是利用公鑰理論和技術建立的提供網絡信息安全服務的基礎設施。PKI管理平臺能夠為網絡中所有需要采用加密和數字簽名等密碼服務的用戶提供所需的密鑰和證書管理,用戶可以利用PKI平臺提供的安全服務進行安全通信。
安全
前端的安全性問題大體上都可歸結為 瀏覽器安全問題,Node.js 可以歸納為另外一個領域。瀏覽器安全問題 又可以細分出來很多問題,比較常見的如:XSS,CSRF,這些問題看似離我們很遠,因為目前我們使用的框架基本上輔助我們已經處理了這些問題,但是整個 Web 世界中還有更多更多我們還未觸及的問題(對于此我也是一個小白),比如:HTTPS 與中間人攻擊,定制瀏覽器的擴展和插件漏洞,目前我主要關注的點在 定制瀏覽器的擴展和插件漏洞 這一塊,這個事情因為和我在處理的問題息息相關,但又和傳統的 Web 安全問題有了顯著的區別:
- 權限更高的 API
- Content Script 劫持
- 中間人攻擊
- 各種“內核”級別的攻擊
歸納起來對于權限的授權,我們應該只申請本插件只使用的 API ,千萬不可使用 * 或all_url 的形式,對于 CS 被劫持的問題,可以給網頁注入的內容添加一個哈希運算,比如前面我們用到的單向散列函數來進行計算。
安全是一個特別綜合性的體系,單一的前端技能可能在這上面能發揮的認知會比較有限,這里的認知 意味著同樣的一件事情,安全工程師能從這里了解到前前后后可能出現的問題。
舉個例子:我們都知道 location 可以獲取 URL 上的各種參數,其實如果黑客利用URL中的某些關鍵信息偽造了一個釣魚網站,用戶是極容易中獎的。
另外一個典型的 CSRF 問題,有著比較復雜的流程,但是它利用的還是瀏覽器中處理 cookie 的機制:
- 受害者登錄 a.com,并保留了登錄Cookie
- 攻擊者引誘(黃色網站)受害者訪問 b.com
- b.com 向 a.com 發送一個請求 a.com/xxx=123,根據瀏覽器處理 Cookie 的機制,此時發起的請求會攜帶a.com 的 Cookie
- a.com 接收請求后,對請求進行驗證,此時已經確認是受害者發起的請求
a.com 以受害者的名義執行了xxx=123
當然解決這個安全問題,業界已經為我們總結了很多方案,比如 同源檢測,Origin Header等等。不過,大體上前端的安全性我們能注重一些常見問題,基本上能涵蓋80%以上的問題。
對于安全問題,業界大佬推薦使用 https://msdn.microsoft.com/zh-cn/magazine/dd347831.aspx?f=255&MSPPError=-2147217396 來創建威脅模型,被歸納為STRIDE 威脅建模,它分為如下六個緯度:
- Spoofing
- Tampering
- Repudiation
- Information Disclosure
- Denial of Service
- Elevation of Privilege
大體上這六個緯度就已經涵蓋了幾乎所有的安全性問題。那么對于前端的項目,我們可以從這六個緯度中去評估自己的項目而得到答案。
隱私和廣而告之
談及隱私是因為如今越演越烈的隱私泄露,大數據等技術的成熟度將一個人的畫像描繪的越來越清晰,數據幾乎就是“錢”的代名詞。
可是對于前端而言(Web世界里),隱私的泄露和 `Cookie` `localStorage` 息息相關。如今的 Web 世界里被追蹤的腳本大多數是用 Cookie 來實現的,簡單的來說多數網站的登錄持久化基本上都依賴于存儲在你設備上的 Cookie,而對于廣告平臺的第三方 Cookie 除了隱私問題外,很有可能還有 `安全性` 的問題,如果這個腳本被劫持了的話,但大多數瀏覽器都默認提供了屏蔽第三方 Cookie,后來大家想到的是通過 `localStorage` 的方案去繞過被屏蔽的第三方 Cookie,這種越演越烈的廣告腳本追蹤,幾乎就是你瀏覽網頁在 Web 的世界里被泄露隱私的來源之一。
有時候真的很想要一個不被追蹤而又能搜索數據的搜索引擎,但久久不可詢,`隱私` 真是一個可愛可恨的事情,除非有人能去做這樣的事情。正好 https://mijisou.com 秘跡搜是一個真正可以保護你個人隱私的網絡搜索服務,它不會記錄任何你的查詢關鍵字,也從不存儲你的個人信息,不傳播你的任何信息,真正做到搜索不留痕,擺脫你不想要的定向廣告的騷擾和可能的隱私泄露,它完美的符合了我的預期。