--- title: 成為看起來很強的後端 tags: Blue 的學習紀錄 --- # 成為看起來很強的後端 [成為看起來很強的後端](https://www.youtube.com/playlist?list=PLS5AiLcCHgNxd341NwuY9EOpVvY5Z8VOs)的閱讀心得 文章內容以影片裡點到但我不熟悉的部分為主 並不是影片內容的完整介紹 ## 04 網路是如何運作的-從瀏覽器到伺服器 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/NaU1jRL4p6s" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ==Proxy==: 中文為「代理」的意思 簡單的介紹可以看這篇 http://macgyver.info.fju.edu.tw/docs/whatisproxy.html https://www.cloudflare.com/zh-tw/learning/cdn/glossary/reverse-proxy/ 簡單來說 就是「使用者」和要連線的「目標伺服器」之間 「使用者」需要多經過一個「Proxy Server」才能連線到「目標伺服器」 這樣做主要的好處是減少對外流量的需求 因為「使用者」需要的內容已經存在「Proxy Server」裡面 較多的介紹可以看這篇 https://www.varonis.com/blog/what-is-a-proxy-server/ 「Proxy Server」除了可以藉由減少對外流量而增加效率 還可以做內容限制,禁止特定 IP 的存取 或是保護使用者的身分,因為外界只知道 IP 來自於某個「Proxy Server」 但不知道確切是哪一個「使用者」 ==Reverse Proxy==: 「反向代理」 「Proxy」的服務對象為「End User」 是「User」與網際網路之間的代理 則「Reverse Proxy」的服務對象為「Server」 是「Server」與網際網路之間的代理 使用目的一樣主要是為了增進效率 也就是所謂的「==Load Balancing==」 或者是將常被訪問的靜態資源直接儲存在「Reverse Proxy」 這樣就不必經過「Server」的資源來處理這個請求 ## 05 網路是如何運作的-TCP/IP四層模型 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/2UWiTaIxukY" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 參考文章 http://linux.vbird.org/linux_server/0110network_basic.php#whatisnetwork_osi 網路架構有 ==OSI 七層架構== 和 ==TCP/IP 四層架構== 這兩種解釋 OSI 為 TCP/IP 的詳細版本 以前在學校時也學過 OSI,但沒留下太多印象 看了影片介紹 TCP/IP 後 覺得比較適合我這種想做後端而不是電信工程師的人去學 不容易忘而且可以對整個概念都略懂略懂 - 應用層 HTTP(HTTPS)、SMTP、POP3、FTP - 傳輸層 TCP、UDP - 網路層 IP(IPv4、IPv6) - 連接層 物理層 ## 06 網路是如何運作的-常見的應用層協議 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/zodKj_nEvZI" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: ==HTTP==: 一種目前 web 應用上最常見通訊協議 所謂「通訊協議」指的是規定好的溝通方式 規定溝通的雙方必須按照這個方式來做溝通 ==FTP==: 與「檔案傳輸」有關的通訊協議 ==SMTP/POP3==: 與「Email」有關的通訊協議 ==WS,Web Socket==: 如果說 HTTP 就像是雙方在網路上一來一往的傳送文字訊息 則 WS 就像是建立了一個通道 雙方打電話直接進行口語溝通 優點是速度快 缺點是占用資源高(成本高) ==SSH,Secure Shell==: 需要「金鑰」才能進行的連線 常見於對「Server」進行 SSH 連線 ==RTSP,Real Time Streaming Protocol==: 應用於「即時串流」的通訊協議 ## 07 網路是如何運作的-HTTP協定 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/vF5t1q-ot4o" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 參考文章: https://www.httpwatch.com/httpgallery/introduction/ Hyper Text Transfer Protocol HTTP 由 ==Header== 和 ==Body== 組成 Header 裡常見的資訊有: - Method GET、POST、UPDATE、DELETE - Host 欲要連線的 hostname - Path 欲要連線的 host 的 path - User-Agent 連線者的瀏覽器名稱 若為 GET 的 request Body 裡可能就沒有資料 若為 POST 的 request 會存放相關資料在 Body 裡 ## 09 HTTP 狀態碼 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/pSNB_8R6vTg" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 參考資料 https://en.wikipedia.org/wiki/List_of_HTTP_status_codes ### 2xx success request 被成功的處理 - 200 OK - 201 Created - 204 No Content ### 3xx redirection 希望 user 轉去其他地方 ### 4xx client errors - 400 Bad Request - 401 Unauthorized 驗證(Authentication)失敗 - 403 Forbidden 授權(Authorization)失敗 - 404 Not Found 401 表示未登入或登入失敗 403 表示拒絕已登入者的請求 ### 5xx server errors - 500 Internal Server Error 通用的錯誤碼 - 502 Bad Gateway - 504 Gateway Timeout ## 10 Token 類型 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/ITDrxC6hDh0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: ### Event-based 與事件相關 通常是一次性使用,譬如簡訊認證 所以又稱為 OTP(One-Time Password) ### Time-based 與時間相關,具有時效性 通常大家在講的 Token 就是指這種具有時效性的 Token ### Static 俗稱為密碼 就是一般的 Password ## 11 雜湊、12 編碼、13 加密 所謂的雜湊、編碼、加密之間,到底有什麼差別? ### 雜湊 Hash :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/orx9V1Iq8wU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 單向 經由不特定的 Hash function 將 A 變成 B 而 B 很難變回 A Hash function 的例子: md5、sha256 ### 編碼 Encode :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/q778N8_RDwk" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 雙向 經由不特定的 Encode function 將 A 變成 B 經由不特定的 Decode function B 可再變回 A 常用於轉換資料的格式 譬如將檔案 壓縮/解壓縮 或是 圖片/文字 轉換的 Base64 ### 加密 Encrypt :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/BBp4Dl2b578" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 雙向 經由不特定的 Encrypt function 透過「鑰匙 A」將 A 變成 B 經由不特定的 Decrypt function B 可透過「鑰匙 B」變回 A 根據「鑰匙 A」和「鑰匙 B」的情況 可以再細分成對稱加密和非對稱加密 若「鑰匙 A」等於「鑰匙 B」 鎖起來和解鎖的鑰匙相同,則為對稱加密 若「鑰匙 A」不等於「鑰匙 B」 鎖起來和解鎖的鑰匙不同,則為非對稱加密 對稱加密的例子: AES 非對稱加密的例子: SSL(HTTPS 的加密方式) ## 14 如何儲存密碼 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/7eBRsPX1a80" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 所以使用者的資料 該用雜湊、編碼、加密哪種做儲存比較好? 這個問題沒有絕對的答案 因為不同的做法各有其適合的場景 好處和成本也各有不同 以「使用者的密碼」來說 如果用 Encode 的方式儲存 則只要知道 Decode function,就能存取使用者的密碼 這樣不行 如果用 Encrypt 的方式儲存 則擁有鑰匙的人(也許是工程師、也許是駭客),也能輕易存取使用者的密碼 這樣不行 如果用 Hash 的方式儲存 則想要得到「使用者的密碼」就得要破解 Hash function Hash function 的特性是單向的轉換 依據不同的 Hash function,其破解難度也有所不同 一個簡單增加破解難度的方式是 Salting 或者是 Hash 之後再 Hash 若擁有無限的時間 不存在破解不了的系統 設計者能做的只有盡可能增加破解的成本 但通常 Hash 的方法越複雜,伺服器就越需要更多資源做運算 所以取得安全性及效率的平衡,就是設計者的工作 既然用 Hash 的方式 伺服器也不知道使用者真正的密碼是什麼 那麼如何驗證使用者輸入的密碼是正確的? 答案是,使用者註冊帳號時,資料庫裡存的是 Hash 過後的密碼 將來要比對密碼時,是將輸入 Hash 過後再與資料庫裡的密碼比對 這樣雖然伺服器並不知道真正的密碼是什麼 但可以做到驗證是否正確 ## Authentication 的範例 ### 15 API Key :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/Ct_YipUgfjg" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: API key 放於 HTTP 的 Header 裡面傳送給對方 常用於 Server to Server 的情境 不適用於 Client to Server 的情境 原因是 Client 很可能會(被)洩漏其 API key 導致其他 Client(包括惡意使用者)可輕易取得他人的 API key ### 16 HTTP Basic Authentication :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/-MZHU9h7mMw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 和 API key 一樣 將 token 資訊放在 HTTP Header 裡傳遞 仍然只適用於內部系統或 Server to Server 差別在於 HTTP Basic Authentication 除了是 HTTP 內建的做法以外 傳遞的資訊還包含了使用者的身分 而不是只有 API key 所以相比於 API key 多了辨別使用者的功能 ## JWT:Json Web Token 官方網站:https://jwt.io/ Handbook:https://auth0.com/resources/ebooks/jwt-handbook JWT 主要用於 login system 包含: - Authentication - Authorization - Federated identity - Client-side sessions (“stateless” sessions) - Client-side secrets ### 18 初探-JOSE :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/EgohBw-LMSw" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: JOSE 為 JWT 的規範 - JWS:JSON Web Signatures - JWE:JSON Web Encryption - JWK:JSON Web Keys - JWA:JSON Web Algorithms ### 19 JWT 的運作機制 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/U2g3k9_NRMA" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 在 HTTP 的 header 內 相較於 Basic Authentication 用的是 `Authentication:Basic` 要使用 JWT 時,要用的是 `Authentication:Bearer` 使用者將登入資訊放在 HTTP body 裡面 伺服器驗證成功後,回傳 JWT 給 user 之後 user 只要帶著這個 JWT 與伺服器溝通,就不必再次驗證 It is important to stress that a signature does not prevent other parties from reading the contents inside the JWT. This is what encryption is meant to do ### JWT 原理與組成 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/29CE6uK7jIU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: JWT 由三個部分組成:Header、Payload、Signature - **Header** 這個 JWT 的相關資訊 例如 JWT 是否被 signed 或 encrypted? 用的演算法是什麼? 根據不同種類的 JWT,header 內必須含有的 field 也會有所不同 以一個未加密的 JWT 來說 只需要擁有 `alg` 這個 field 設置為 `"alg": "none"` 所以最簡單的 JWT header 會長這樣: ```json= { "alg": "none" } ``` header 的內容是以 Base64Url 的方式進行傳輸 - **Payload** 要傳送的內容 譬如 token、帳號名稱、email ```json= { "sub": "1234567890", "name": "John Doe", "admin": true } ``` 要注意的是 Payload 的內容也是以 Base64Url 的方式進行傳輸 ==所以 Payload 不能存放機密資訊== ![](https://i.imgur.com/5udonG9.png) > 圖片來源:https://auth0.com/resources/ebooks/jwt-handbook - **Signature** 根據 header 和 payload 的內容 加密而成的一段文字 加密的金鑰只有 server 才知道 所以當惡意使用者更改了 JWT 的內容 卻又無法計算出相應的 signature 時 其內容就無法符合 signature 進而做到資料驗證 ## 什麼是 Session? :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/DceuW3gxbNg" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: HTTP 的每個 request 都是獨立的 伺服器並不知道兩個不同的 request 之間是否有任何關係 也就是所謂的無狀態 stateless 但現實實務中,我們會需要會員系統、購物車系統這類服務,這類服務需要能辨別不同 request 之間的關係 譬如說登入 facebook 後,我們不會希望每按一個讚或留一個言之前,都還要再輸入一次帳號密碼。也就是,伺服器如何知道你已經登入了? 如何讓各個不同 request 之間的資訊流動(stateful) 這個機制就叫做 session ## Cookie 運作方式 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/NUGMceeFDnU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 一句話:==儲存在瀏覽器==裡的==小份資料== 當 server 回傳的 respone 內含有 `Set-Cookie` 這個 field 時 瀏覽器就會自動記錄這筆 cookie 資訊 瀏覽器==自動==在下一次的 request header 就會帶入 cookie 的資訊 ## Cookie 常見屬性 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/siJ6FlxmwJg" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: ### 作用域相關設定 第一方 cookie?第三方 cookie? 已知瀏覽器從 server 的 respond 收到 cookie 後 在接下來的 request 中就會帶入 cookie 但瀏覽器怎麼知道各個 cookie 屬於哪個 host?在哪個 path 才要帶上 cookie? - Domain 在哪些 domain,瀏覽器會自動帶上 cookie? - Path 在 cookie 裡加入 domain 和 path 的屬性 瀏覽器就知道在哪些 host 該送 cookie - SameSite 可設定成 Strict / Lax / None 內容可參考:https://ithelp.ithome.com.tw/articles/10251288 ### 過期相關設定 - Expires 過期的絕對時間 譬如:2021/02/07 - Max-Age 過期的相對時間,從 cookie 被產生後開始計算 譬如:一天 擁有 Expires 或 Max-Age 其中一個屬性的 cookie 又被稱為 Persistent Cookie 表示可以持久性的存在 不會因為瀏覽器關閉而消失 相對的另一種 cookie 稱為 Session Cookie 這裡的 Session 指的是瀏覽器的 Session 也就是若瀏覽器關閉了,這個 cookie 也會跟著消失 ### 安全相關設定 - Secure 限定在 HTTPS 的條件下才會傳送 cookie - HttpOnly 禁止 Javascript 取得 cookie ## Session-based Cookie v.s. Session Store :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/z0wPnx1bfcQ" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 如何確保 cookie 的內容不被竄改? ### Session-based Cookie 將 cookie 內容做加密 但加密的缺點是: - 運算成本 - 檔案增大 通常加密會讓字串長度變更長 所以有機會超出 cookie 的上限 - 仍然可能被破解 因此現代不使用這個方式 ### Session Storage 現代常用的方式 cookie 內不放資料,放的是 ID 資料存放在伺服器端的資料庫 通常是使用 Redis 這個服務來存放 session data ## JWT 跟 Session 一起來 :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/kY7s0OoBY28" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 總結 JWT 和 session cookie 的運作 ```sequence Title: JWT 使用者 -> 伺服器: /login Note right of 伺服器: 驗證登入資訊 伺服器 -> 使用者: JWT (Header Authentication: Bearer) Note left of 使用者: 用某種方式存起來 使用者 -> 伺服器: /pirate (帶著 JWT) Note right of 伺服器: 驗證 JWT 的內容 ``` 常見的儲存 JWT 的方式 - local storage 不安全的方法,JWT 有被偷走的可能性 ```sequence Title: Session cookie 使用者 -> 伺服器: /login Note right of 伺服器: 驗證成功 伺服器 -> 資料庫: 存入登入資訊 資料庫 -> 伺服器: session ID 伺服器 -> 使用者: session ID (Header Set-Cookie) Note left of 使用者: cookie 存入 browser 使用者 -> 伺服器: /pirate (以 cookie 的形式帶著 session ID) 伺服器 -> 資料庫: cookie (session ID) Note right of 資料庫: 驗證 session ID ``` ## JWT 跟 Session 怎麼選? :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/HYUk-o1cE10" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: 單獨使用 JWT 或 cookie session 都會有各自的優缺點需要面對 - JWT 主要問題是 JWT 如何存放的問題 存在 local storage 就表示瀏覽器擁有權限存取這份資料 也就是說,攻擊者可以透過 JS 得到這個 token 能得到 token 就表示可以被竊取 存在 memory,也就是暫存在瀏覽器的話 雖然增加了竊取的難度 但會讓使用者體驗大幅降低 因為瀏覽器關閉時 JWT 也會跟著消失 - cookie session 雖然 cookie 擁有 HttpOnly 的方式來阻止 JS 取得 cookie 每當使用者傳送一次 cookie 給伺服器 伺服器就得要再去查詢 Redis 由於使用者登入後的每一個動作都需要帶有 cookie 所以當使用者數量龐大時 系統需要的負荷量也會相當龐大 ## JWT 跟 Session 怎麼組合? :::spoiler 點擊展開影片 <iframe width="560" height="315" src="https://www.youtube.com/embed/GxhPQl2guXM" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> ::: ### JWT JWT 做到的是,保證傳遞的資訊沒有被**竄改**過 但不能保證資訊不被**讀取** 為了不讓 JWT 被他人讀取 所以想要將 JWT 以 In-memory 的方式儲存 但瀏覽器重整後 JWT 就會消失 ### Cookie cookie 的缺點是過於頻繁的與 session store 做溝通,而且 session store 也難以做水平擴充,因為分散式資料庫要做到即時的資料一致性 靜態頁面不需要透過伺服器做渲染,前後端分離的情境,適合 JWT 伺服器會渲染前端頁面,例如 Express,適合 cookie 在小型的應用時使用者不多,使用 cookie 並沒有問題,但只要使用者一多,伺服器效率就會出現瓶頸