26 January 2014

Http 協定已經不光是網頁在用了,現在的 mobile apps 存取資料大多也是走同個協定,因此設計 web API 給網頁、給 mobile、給 middleware 使用對工程師來說已經是家常便飯、必備技能。本文討論 https 在 web API 中扮演的角色以及最佳實踐。

什麼時候使用 https

Web API 都要走 https 嗎?簡單的答案是 ,不過要更深入一點的話,就要看需求而定。我們可以依 Web API 的作用,簡分成三類:

  • 變更資料 API
  • 取得私有的資料 API
  • 取得公開的資料 API

變更資料 API

變更資料包含新增、修改與刪除。沒有例外,這類的 API 都該全程使用 https,而且需要驗證與授權。沒有 https 的保護,會有被竊聽、篡改、Replay Attack 的危險。

取得私有資料 API

私有資料像是朋友列表、購買紀錄、實驗結果、備忘錄等等任何用戶產生,但只有授權的人才能取得的資料。這類 API 同第一種,也必須使用 https,並且需要驗證與授權。

取得公開的資料 API

公開的資料是大家願意公開分享的,因此放鬆安全的等級 通常 沒什麼大礙。另一方面是為了速度的考量,因為 TLS handshake 的負擔太大,這在 WIFI 上沒什麼感覺,但在 3G 網路上 https 增加大約 1.5 秒的延遲,這時只好退一步選擇 http。

公開的資料本身是沒什麼秘密好保護的,但讀的人可能需要隱私的保障。例如某位用戶使用你開發的 app,讀了很多性病的網路文章,雖然那些文章都是些公開的知識,但有心人可以分析出這位用戶可能有隱疾、及他的病史。這都是因為你的 app 只用了 http。遇到這種情形,還是需要強制使用 https。

一般來說公開資料使用 http 是 ok 的,但如果你的客戶群比較特別,那還是走 https 吧。

Meta data leak

https 可以有效防止竊聽、篡改、Replay 等重要的攻擊,但是它沒辦法保障完全的隱私。它可以避免別人知道你做了什麼,但是別人還是能知道你通常在哪個網站做事、在什麼時段做,和做了多久。一般的資料也許沒有這麼敏感,但涉及醫療病例、或是更極端的軍機就不同了。在軍事上這些 meta data 洩露就很危險,比方說敵人雖不能破解你的內容,但發現你們在攻擊前,經常有大量的資料在某中心交換。一旦被破解出這樣的重覆模式戰局就變了。

https 能加密你存取的 url 中 path, query string, header 以及存取的內容,但沒有保護你去哪個網站 (host)

如果你的 app 有這方面的考量,那就不要用 web 協定。

正確部署 https

好了,談完了如何取捨 https,接下來來看正確的部署 https。資安是個無止盡的工作,你必須與時並進,常常修補伺服器與學習新知。關於 https ,現在有個很棒的線上工具可以替你的網站評分:SSL Labs Site Test,只要輸入你自家的網站,就可以得到 SSL 安全等級的評分:

SSL Labs analyze result
圖說: SSL Labs 對四個安全項目的評分,結果為 A-

SSL Labs 會檢查你的憑證是否過期或設定錯誤;檢查你的網站是否支援最新的 TLS 1.2 標準;檢查交換公私鑰是否有漏洞;檢查加密的演算法是否夠安全。要完全了解每一步的細節要花很多時間研究的,好在要達到高安全性不難,只要設定做對就行了:

  • 升級你的 web server 以及 openssl 到最新版,套用任何已知的安全修補,確定支援 TLS 1.2 協定
  • 開啟 Strict-Transport-Security,這個設定會強制網頁的所有內容都要使用 https 。前面這個 Wikipedia 連結裡就有設定的範例。
  • 移除 SSL2 的支援
  • 關閉 TLS 壓縮,因為 CRIME 漏洞
  • 強化 Forward Secrecy,見下面說明

網路上有很多篇教人怎麼在 apache/nginx server 上完成列出的設定,特別是 Forward Secrecy。可參考 這裡 或是 SSL Labs Blog

Forward Secrecy (向前保密):如果加密用的私鑰重頭到尾都沒變過,一旦某一天私鑰被破了,那之前傳輸的加密內容也會被破解。如果私鑰每次都不一樣,那麼就算被破一次,也能保障之前的內容是安全的。達到這個安全標準就稱做 Forward Secrecy

改完 server 設定後,記得到 SSL Labs 再驗證一次是否拿到 A- 以上。反覆修改設定直到設好為止。

https 的穿透性

有些 ISP 或是中間商會對 http 80 port 進行內容過濾,造成某些環境下 app 或網站不能使用 (例如某些公司內)。這時候 https 443 port 就很重要了,因為內容都是加密的所以過濾器無從干擾,只能放行。所以如果想讓 app 的 web API 在所有奇怪的環境下運作,選擇 https 是比較好的。

而 WebSocket ws:// 更是不用說了,這新的 protocol 雖是掛在 http 之上,但一大堆中繼的硬體和軟體都不支援。所以沒有別的選擇,部署 WebSocket 時就是要採用 TLS tunnel: wss://,走 443 port,才能提高連線成功率。WebSocket 跟 stateless http request 不一樣,它只做一次 handshake 後就一直連著,之後傳送任何資料都沒有 TLS 來回的額外負擔,所以沒有必要捨棄安全性。

小結

在大多數的情況下,你的 web API 應該要走 https。只有取得公開的資料時,為了 mobile 速度的考量,才值得退回 http。要時常更新 server 的安全漏洞,並且利用 SSL Labs 定期檢查 https 的部署是否有疏失。

這次沒討論到 web API 的驗證與授權,那又是另一個大題目了。


回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>