KK 的 Web 實驗室(Day11–16)

Chunhao Weng
14 min readOct 1, 2020

--

iT邦幫忙鐵人賽,越來越精彩

這純粹是自己不知道為什麼想做的事情,紀錄一下 KK 的生命旅程。

Web 實驗室資源:

Youtube

Facebook

以下為 KK 課程內容的文字紀錄,我本人不是KK。(重要)

影片開始。

15 成為看起來很強的後端:API Key

今天 KK 老師會跟我們談兩種「權限驗證」方式。

第一種是 API Key ,打一個 API 的時候會帶著金鑰進行驗證。

第二種是 HTTP Basic 驗證,經常使用在後台、內部系統。

API Key 是什麼?

Custom HTTP headers 通常用 X 開頭

前面有提過 HTTP 的結構,由 Header (表頭)和 Body 組成。

在 Header 裡面有各式各樣表頭,如:Content-Type, Host…等等。

有一種可以自定義的 Custom HTTP headers,通常用 X 作為開頭。

如: X-API-Key 用來定義權限驗證的模式。

admin 定義為 key

當我們要使用一個 API 來呼叫程式、拿資料、更新、刪除…等等的 Request 時,後端會用自己定義的 key (這邊舉例用 admin 作為 key)來確認是否驗證 OK。

如之前影片提過,因為已經有白名單,通常情境用在 Server To Server 這種簡易的驗證上。

API Key 通常使用在 Server To Server

例如我們自己有一個 Server1 伺服器,另外一個第三方的伺服器(如:Facebook 或金流系統)。

使用提供 API Key 的驗證方式,對方伺服器會去資料庫(DB)檢查是否驗證 OK。

如果 API Key 用在 Client To Server 會有什麼問題呢?

因為 Client 端(Web 瀏覽器或 App)需要把 Key 存起來,其他人有機會偷走這個 Key 作為驗證。

這邊提供一個例子,就是 Google Maps 的 API。

KK 老師說,程式寫得好的人,就會把 API Key藏好。

沒寫好的話,常見 Key 裸露在外面,這樣就能在自己的網頁使用別人的 Key 來使用 Google Maps 的 API 。(Google Maps 的 API 需要付費,自然就是 Key 的擁有者付費了。)

所以記得 X-API-Key「不要」使用在 Client To Server 的模式上。

應該如何正確建立、管理 API Key 呢?

設想一個情境,你在公司內負責「交易」(Payments)的模組。

另外一個同事處理「網頁」(Web) 模組,想要跟你呼叫 API 。

這時候要怎麼給同事 Key 呢?

API Key 寫死或放資料庫

第一種方式:寫死

使用環境檔,或是把 Key 定好之後交給 Web team。

通常在寫內部系統時會直接寫死。

第二種方式:放在資料庫裡

這是比較常見的方式,使用資料庫建立、取消、驗證。

如果有在串第三方服務(如: Slack 、 Discord)通常都會有個產生 API Key 的地方,也可以進行刪除。

資料庫模式會長怎樣呢?

Payments 團隊提供一個介面,用來產 API Key

以前面的例子, Payments 團隊可能會提供一個介面,產生 API Key 存在 DB 裡面之後,透過介面提供給 Web 團隊。

之後驗證的時候,Payments 的伺服器就會把 Header 裡面的 Key 拿來看是不是跟 DB 裡面一樣。

如果 OK 的話就把 Web 團隊 Request 的資料傳給對方。

怎麼樣會驗證「不OK」?

第一種:被刪除。

資料庫裡面已經沒有這個 API Key。

第二種:過期。

通常產生 API Key 的時候會設定有效期限,如果驗證的時候發現超過時限,也會驗證不過。

結論:

使用 API Key 的時候,請使用 Server To Server 的模式。(如果使用 Client To Server ,強烈建議不要使用 API Key 的方式。)

自定義 API Key 通常使用 X 當開頭(如: X-API-Key:admin)放在 Header 裡面,也可能被放在 Query String 的 Parameter 裡面。

16 成為看起來很強的後端:HTTP Basic Authentication

Client To Server 就用 HTTP Basic Authentication

如果我想要使用 Client To Server 的模式呢?

接下來要講的是 HTTP Basic Authentication (KK 老師口語會講 Basic Auth)。

這種「多用戶管理模式」,能知道「使用者名稱」又同時有「金鑰」。

跟 API Key 一樣放在 HTTP Header 裡面,但不同的是,使用的不是自制的 Header,而是用 Authorization。

之後的章節可能會用不同的 Authorization 方式,這邊我們使用 Basic 。

Basic 後面接著一個 Token。

前面有談過 Token 的三種模式,Event-based, Time-based, Static。

HTTP Basic Authentication 使用的是 Static 模式,由使用者名稱(username)和密碼 (password) 組成。

如果平常聽到 Key 或 Secret ,代表沒有「使用者」的概念。

而使用 username 和 password 就能做到「多用戶權限驗證」,每個「使用者」有各自的密碼作為驗證用。

HTTP 傳輸的時候如果遇到非法(特殊)字元該怎麼辦?

有些人使用者名稱或密碼會輸入特數字元,如:@, !, 空白…等。

此時可以透過先前介紹過的編碼轉換。

HTTP Basic Authentication 使用 Base64 編碼。

如果 Client 端依然要顯示使用者名稱與密碼,跟 API Key 有什麼差別?

HTTP Basic Authentication 有一個 Challenge 機制 (Challenge-response authentication),Server 可以設定是否做 Challenge。

https://en.wikipedia.org/wiki/Challenge%E2%80%93response_authentication

具體來說,Client 端會出現一個彈跳視窗,讓使用者輸入帳號、密碼。

Challenge 會跳出視窗讓使用者輸入

KK 建議我們可以去 Google 一下, MDN 這裡說明得滿清楚。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication

用 HTTP Basic Authentication 時要如何管理帳號、密碼呢?

假設有一個 Client 端要跟 Server 互動,如:公司內部的數據後台或訂單管理後台。

這時會 Client 端會跳出一個 Challenge 要求輸入帳號、密碼。

輸入完之後,HTTP Basic Authentication 回覆伺服器。

後台有兩種做法,要不然存 DB,要不然寫死。

寫死最常見的做法,就是在 Server 裡存一個檔案(File),存著帳號、密碼資料。

Server 裡存一個 File

講到目前為止, HTTP Basic Authentication 還是有一個基本問題,就是 Base64 編碼是雙向的。

因此傳輸的時候 HTTP Header 的內容有可能被看到。

之後幾個單元 KK 老師會談談 API Key 和 HTTP Basic Authorization 之外,更安全、業界常用的方式。

17 成為看起來很強的後端:登入有這麼簡單?

各種 login 方式

同樣是輸入帳號、密碼,HTTP Basic Authentication 跟會員登入系統差別到底在哪呢?

最主要的差異:HTTP Basic Authentication 「沒有」登入介面。

各位可以想想,如果我們想在公司做一個數據後台,需要限制特定人使用,難道要實作一個會員登入系統嗎?

這時用 HTTP Basic Authentication 就很適合,把有權限的頁面加一層防護(middleware),用 Challenge 使 Client 端彈出驗證頁面。

那一般的會員登入是如何實作的呢?

第一種:登入的時候發一個 login 請求、username 是 kk、密碼是 1234。

第二種:登入使用 HTTP Basic Authentication

如前面所提到,HTTP Basic Authentication 是在懶得做登入介面的時候使用,通常不會在 login 請求使用。

可能會在內部才看得到的頁面做防護,如 /private 、 /orders 、 /sales 這樣的頁面。

第三種:使用 Body (非 Header)做登入機制

那到底第一種還是第三種好呢?

假設是第一種, username 和 password 都會被放在網址裡面。

瀏覽器會有網頁的歷史瀏覽紀錄。

你的帳號、密碼都會被看光光。

第一種放網址,帳號、密碼看光光

因此我們會選擇第三種,把資訊放在 HTTP 的 Body 裡面。

除了前面提到瀏覽器的歷史紀錄之外,伺服器也會把請求(Request)的資訊記錄下來。

而這些日誌(log)可能不只是工程師在看,也可能有其他的人會看到。

最後再區分一次,這段談一般使用者登入認證和 HTTP Basic Authentication 的差異。

想要做登入頁面、會員系統的話,就用簡單的帳號密碼登入,把資訊放在 HTTP POST 的 Body 裡面。

如果不想要自己實作,想要讓頁面有基本的 Challenge 認證,就用 HTTP Basic Authentication。

下個單元,KK 老師會繼續講,各種 POST Body 之後的 JWT 和 Session 、 Cookie 的運作。

18 成為看起來很強的後端:JWT 初探-JOSE

JSON Web Token 與 JOSE

JWT 全名為 JSON Web Token ,也是一種驗證機制。

前面談的一些機制,比較常用在 Server To Server 或用在簡單的 Client 端認證。

實際上在做登入系統時,如何去保持登入狀態,不用每換一頁就進行帳號密碼驗證,就是 JWT 要解決的問題。

JSON 是種常見的網頁結構,是用大括弧、 Key 、 Value 的格式所組成。

之前的影片也提過 Token 有分三種:Event-based, Time-based, Static。

JWT 用的是 Time-based 的驗證模式。

這邊簡單介紹 JOSE 規範 (Javascript Object Signing and Encryption)。

在做 JWT 的時候可能會涉及演算法、金鑰、加密、簽署模式…。

JWA:Algorithm,定義哪些演算法可以產生 Token 。

JWK: Key,用到的金鑰要怎麼產生、用多少位元,都是JWK 規範。

JWE:Encryption,規範如何加密、加密幾次…。

JWS:Signature,如何簽署 Token,意即如何驗證 Token 是正確的。

KK 老師說:這個規則完全不用去記,因為我們要成為「看起來很強的後端」,能夠講出「喔喔,JWK 是定義 Key 的」以及這幾種規範不要搞混就好。

JWT 如何紀錄登入狀態的呢?

前面 HTTP Basic Authentication 的 Authorization 是接 Basic。

而 JWT 則是 Authorizaiton 接 Bearer 以及 Token。

KK 老師也趁機談談一些錯誤範例(Anti-pattern),請不要寫成 JWT 。

JWT 用的是 Bearer 不是 JWT!!!

19 成為看起來很強的後端:JWT 的運作機制

在瀏覽器收到 Challenge 且使用者成功登入後,因為 HTTP Basic Authentication 沒有提供登出方法,使用者將無法直接登出。

這就是為什麼 Basic 通常用在內部系統。(可能要開無痕模式或用其他方式處理。)

如果希望使用者可以不用持續的傳輸帳號、密碼給伺服器,又不想把使用者的帳號、密碼存起來,要怎麼做?

首先 Client 端在 /login 的 body 裡面帶入 username 和 password 。

伺服器收到 Request 之後去 DB 做驗證,確定沒問題之後,伺服器產一個 token 給 Client 端(JWT)。

好處是,就算別人拿到你的 Token 也無法取得你的帳號、密碼。

因此接下來的挑戰就是,如何防止別人拿到 Token。

目前常見也比較不安全的做法,就是把 JWT 存在 Client 端的瀏覽器裡面。

KK老師說,之後會來談談 modern web 比較注重資安的做法。

講了這麼多,JWT 到底有什麼好處?

除了亂碼之外,如果不想要這麼頻繁地跟伺服器要資料的話(如:使用者名稱、使用者 email…),就可以把資料放在 Token 裡面一起帶回來。

20 成為看起來很強的後端:JWT 原理與組成

JWT 由三樣東西組成:Header、Payload、Signature。

Header 指的是這個 token 用什麼演算法(Algorithm)、什麼型態(Type)產生出來。

Payload 指的是 token 的隱含資訊,如:使用者是誰、email…等。

重要: Payload 裡面不可以放機密資訊(如:密碼)

為什麼 Payload 裡面不可以放機密資訊?

Header 是 Algorithm 和 Type 以 Base64 (因為可能有非法字元)組成的 JSON 資料。

Payload 也是以 Base64 組成的 data。

如果 Payload 放機密資訊,用 Base64 解碼就可獲得。

Signature 將前面的 Header 、 Payload 加上一個 Secret,通通 Hash 起來,作為 token 是否正確的驗證。

因此如果有人拿到你的 token 嘗試串改前面的資訊,此時 Hash 出來的 Signature 就會錯誤。

這樣的特性允許 Signature 做到「無狀態驗證」。

意思就是每個 Request 都獨立存在,不需要仰賴一個 DB 去處存帳號、密碼是什麼。

只要有一把 Secret 就能跟對方有很好的權限方式,也更容易擴張驗證系統。

幾個 JWT 的重點

第一個是 JWT 的保存方式,比較不好的方式就是存在 Local Storage ,之後會介紹比較好的方式。

第二個是 Payload 不要放機密資訊, token 是有可能被拿走的。

第三個屬於「無狀態驗證」的特性。之後談到有狀態的驗證可以來比較看看。

而 Header 的演算法也有幾種,如: HMAC(如:HS256)、RSA(如:RS256)。

請自行 Google關鍵字

KK 加油!

有興趣請直接去 Web 實驗室的 Youtube 跟 Facebook 社團吧。

Web 實驗室資源:

Youtube

Facebook

--

--

Chunhao Weng
Chunhao Weng

Written by Chunhao Weng

Random notes for personal use.

Responses (1)

Write a response