JWT & SendGrid - 實作電商忘記密碼

前言 前陣子參與一個電商的開發案,參考一些開源專案的設計,包含火紅的 Shopify 替代方案-Medusa,研究完後大致了解該怎麼實作和設計一系列跟密碼重設、忘記密碼、註冊登入…等電商功能,所以就有了此篇文章來紀錄一下過程,實作內容是 Medusa 的原始碼,會以一個 high-level 的設計來闡述設計的流程與該注意的事項 以使用者觀點來看忘記密碼/重設密碼這件事 一般來說,我們在用任何有登入、註冊相關的網站,都會有「忘記密碼」的按鈕,但實際上網站後台的資料庫並不會存我們密碼的明碼(理論上都不應該 QQ),所以當按下忘記密碼後,我們會收到一個電子信箱,裡頭並不會原封不動地將我們的密碼傳回來,因為該網站的資料庫存的是 hashed 過後的密碼,而 hash 是無法被逆向回推的,所以這時候信件裡應該是一組 url,點擊後會跳轉到該網站寫好的重設密碼的頁面,讓該使用者輸入密碼與確認密碼,以便重新設定一組新密碼. 例如下圖的 email 截圖,圖片來源: https://designmodo.com/reset-password-emails/ 以上就是一般使用者的操作流程,這些流程大家都再熟悉不過,但背後的系統流程是怎麼運做的呢? 簡述設計流程 既然要收發信件,肯定需要有寄信服務,寄送信件的服務有很多種,最常見的就是SendGrid,我在實作中有註冊一組帳號來取得發送 email 的 token,但後來開發上有受到一些阻礙與問題,最終改用 這篇文章 和 這篇文章 提到的 GCP 支援的 SendGrid Email API 免費方案來完成寄信功能,目前運作起來一切正常 有了寄信服務之後,接下來要解決的是怎麼確保重設密碼的人就是該帳號的擁有者,避免中間過程被盜取身份,竄改該使用者的密碼? 這個問題是最關鍵的,也就是身份認證的資安議題 一般來說,身份認證(Authentication)肯定會需要 DB 來儲存該 user 的個人資料與帳號密碼,因此實作中我使用 PostgreSQL 作為 DB 的選用,而現今認證機制大多使用 JWT,好處是省去 server 再拿 session id 撈一次資料庫的成本,直接用 base64 將 payload 內容 decode,拿到其中就算公開也沒差的無隱私資料,例如:user id,接著服務當場拿該 user id 去問 DB 該 user 的資料,當然也會帶著 JWT token 去詢問,此時 JWT 的第三部分(signature)的 secret 就是判斷該 token 是否有被篡改的依據,若成功驗證,就能成功取得該 user 的資料,完成身份認證(Authentication)甚至授權(Authorization)的流程...

<span title='2023-02-27 00:49:13 +0800 +0800'>February 27, 2023</span>&nbsp;·&nbsp;5 min&nbsp;·&nbsp;923 words&nbsp;·&nbsp;Madi