KK 的 Web 實驗室(Day20–22)

Chunhao Weng
10 min readOct 9, 2020

有時候莫名還是吃了火鍋

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

Web 實驗室資源:

Youtube

Facebook

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

影片開始。

24 成為看起來很強的後端:Cookie 常見屬性

這支影片開始,kk 老師的聲音變得比較和緩,而且清晰許多。

現在的影片如果用 1.5 倍速聽就會比較像之前的語速。

而且聲音也變得更深層好聽,滿有趣的變化。

先來複習 Session 和 Cookie 的機制

Client 端 Browser 打一個 /login 給 Sever ,Server 在 Response Header 回傳一個 Set-Cookie: sid = xxx。

Set-Cookie 有兩種做法

一種方式是 Set 已經加密好的資料。

另一種方式是比較常見也是我們這裡使用的,存 session ID 。

sid = session ID

Session store 裡面會有一張表,存著我們的 sid (xxx) 和存了什麼字。

Session store

Browser 也會自動幫我們把 Server 回傳的 sid = xxx 存起來。

假設這是一個電商網站,想下單,打一個 /orders ,Browser 會在 Request Header 自動帶上 Cookie: sid = xxx。

Browser 自動帶 Cookie 資訊,Session store 做驗證

Server 會去 Session store 做檢查,沒問題之後,就把資料回傳。

複習完畢。

這樣會有什麼問題呢?

第一個問題是「作用域」的問題

什麼情況下, Browser 會自動幫我們帶 sid = xxx 過去?

根據不同的 Server 我們有「第一方 Cookie」跟「第三方 Cookie」模式。

「第一方 Cookie」網域(domain)會是相同的。

舉例來說,Browser 網址的位置是 www.example.com ,Server 的位置是 api.example.com

Client 跟 Server 都是相同網域 ( .example.com )

如果網域不相同,則稱為「第三方 Cookie」。

例如:天貓或掏寶背後都是阿里巴巴。

Client 端的 .example.com 其實連到其他網域 api.qq.com

另外一個例子就是我們平常會聽到的「跨網域追蹤」,透過在網站內埋碼,利用臉書或Google追蹤、分析使用者行為。

例如:電商網站(Browser)放臉書的追蹤碼(Server),這種也是「第三方 Cookie」。

有些瀏覽器會預設把「跨網域追蹤」選項關掉,網站就無法把這些資料傳給第三方。

但如果網域相同,可能會造成無法登入的情形。

好處是可以防止廣告商分析,壞處可能是大型集團共用 api 就需要針對這個情形做調整。

各種屬性(限定使用區域、限定使用時間)

我們先談談「限定使用區域的屬性」。

Set-Cookie:sid=xxx 後方會有屬性。

第一個是 Domain,可以指定哪一些網站要帶 Cookie 過去。

例如:Domain 設定為 api.example.com ,這樣其他的就不會帶過去。

Domain 屬性,限制特定網站帶 Cookie

第二個是 Path ,之前談 HTTP 有提過,就是網域斜線後面的路徑。

例如: 設定為 Path = /login, /order ,只有這些路徑才會把 Cookie 帶過去。

Path 屬性,限制特定路徑

第三個是 Secure ,如果你的 api 沒有 HTTPS 就不會帶 Cookie 過去。

Secure 就是 HTTPS 啦

接著談談「限定使用時間的屬性」。

使用 Expires ,就能限制到某一個特定時間點,如: 2020/1/1。

使用 Max-Age ,就能限制固定時間內使用,如: 1 day 。

Persistent Cookie ,看限制條件才會刪除 Cookie

設定上面這兩種屬性,Browser 內部就會啟動計時器,在適當的時間把 Cookie 刪除。

而這種稱為 Persistent Cookie ,就算關掉分頁、瀏覽器,只要條件沒有符合,Cookie 就會在。

Session Cookie ,Session 結束就沒了

反之稱為 Session Cookie 。(還記得嗎?前面提過 Session 指的是「一段時間內」的「狀態」。)

所以關掉之後,就會消失。

這邊補充比較特殊的「限定使用區域的屬性」。

SameSite 屬性

SameSite 有三種模式: Strict、None、Lax 。

設定 Strict 只允許網域相同的「第一方 Cookie 」。

設定 None 就是不管什麼作用域都會帶 Cookie。

設定 Lax 就要看情形,如果是 GET 的 Request 就不管網域、而 POST 和其他的 Request 網域需要相同。

不過,以上這些都是屬於 Server 端控制的,就算你通通允許,Browser 如果有擋,那也沒有用。

(這段我一直以為窗外有貓…原來戴耳機聽影片這麼真實)

Browser 是怎麼儲存 Cookie 的呢?

使用者、開發者是有可能拿 Cookie 做一些事情的,此時就可以用 HttpOnly 的 flag 。

瀏覽器就會知道,這個 Cookie 禁止被 JavaScript 存取(預設可以拿到 sid),只有在傳輸的時候透過瀏覽器傳輸才能。

25 成為看起來很強的後端:JWT 跟 Session 一起來

目前業界到底是怎麼比較安全的做權限驗證、儲存 Token 呢?

快速複習一下 JWT 和 Session 。

JWT

JWT 是透過 Browser 打一個 /login 給 Server ,Browser 的 Response Header 帶 token ,由 Browser 存起來。

重點是,Request 的時候是使用 Authorization: Bearer 後面接一個 Token 。

Session 或 Cookie

Cookie (有些人稱為 Session)的做法是 Server 的 Response 會把 Session ID 透過 Set-Cookie:sid=xxx 帶回來。

Browser 會自動存起來,下一次 Request 的時候, Server 會透過 Session Store 來驗證。

Browser 如何儲存 JWT 的 Token ?

普遍來說,有兩種做法:

一種是 Local Storage ,後面的章節 KK 老師會做詳細的介紹,類似本地端的硬碟,Browser 有個小區,會存 token=xxx 。

而 Browser 在 local storage 有儲存,就代表 JavaScript 可以存取。

如果別人安插腳本進來,或是使用者的資安意識薄弱,拿到 Token 之後外洩,這都會造成問題。

所以要如何儲存,卻不被拿到?

另一種做法是之前有提過的 HttpOnly Cookie,因為只有瀏覽器能取得和傳輸使用。

HttpOnly Cookie,無法透過 JavaScript 存取

為了說明方便,我們暫時稱為 JWT 2.0

一樣從 Browser 打一個 /login 到 Server , Server 的 Response 為 Set-Cookie: token = xxx HttpOnly 。

記得 JWT 是 Stateless 的模式,因此 Server 端並沒有儲存的需要。

Browser 也在裡面存的 token=xxx。

JWT 2.0 只是暫時的描述方式

這邊會遇到一個問題,因為 Cookie 是 Browser 自動帶的,而 token 必須在 Header 使用 Authorization: Bearer 的方式。

當 Browser 自動帶 Cookie: token=xxx ,Server 收到之後…看不懂,無法 handle 。

一種解決方法是,有些後端會不管標準模型,直接把這個 token 拿去驗證。

但標準作法,要用 Authorization 這樣的方式,該怎麼做?

26 成為看起來很強的後端:JWT 跟 Session 怎麼選?

一個可能的作法,是不是直接用 JavaScript 把 Header 改成 Authorization?

但,如果要用 JavaScript 去改 Header,那就需要拿到資料。

如果你要拿到資料,但這裡可是 HttpOnly 啊。

HttpOnly 可是 Javascript 拿不到資料的

看來 JWT 需要靠 Client 端幫助。

當我們「第一次」透過 /get-JWT 把 token=xxx 傳給 Server 的時候,Server 會回傳一個真正的 Token 。

而「第二次」透過 /private 的時候,就可以放 Authorization: Bearer JWT 。

等等,那如果回傳的 JWT 要存放,那不就還是一樣的問題嗎?

回傳的 JWT 要存在哪呢?

這時候就能透過 In-Memory 的存放,不存放在任何地方,而是留在記憶體裡面。

可以想成,我們用個變數儲存,重新整理就會消失。

這個把 Session/Cookie 跟 JWT 整合的模式,就是這一、兩年常見的模式。

以前面的例子來說,「第一次」帶給 Server 的 token 稱為 Refresh Token

(幫我們 JWT 做 refresh 的 token,透過 Refresh Token 的 API 把 token 帶給 Server )

「第一次」帶給 Server 的 Refresh Token

「第二次」拿到的 token 則有些人稱為 Auth Token (較常見)或 Access Token

所以,我們「第一次」透過 Refresh Token 拿到 Auth Token。

而「第二次」使用的 Auth Token 會記錄所有跟權限有關的資訊,使用 JWT 的格式實作。

那到底為什麼要做這麼麻煩呢?

To be continued…

有興趣的歡迎去 Web 實驗室的 Youtube 跟 Facebook 社團唷。

Web 實驗室資源:

Youtube

Facebook

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Chunhao Weng
Chunhao Weng

Written by Chunhao Weng

Random notes for personal use.

Responses (1)

Write a response