---
# System prepended metadata

title: 驗證與安全性

---


## 驗證流程設計(先借丟)

我只知道大概原理流程，並沒有實作過，以下是我研究的結果:

### 採用JWT進行身分驗證

1. 如果前後端分離(SPA)架構的話JWT會比較好做
2. 而且微服務在不同的伺服器上話會有共享session的問題，而JWT本身就自帶驗證資訊(無狀態)就不需要session共享
3. 請求身分驗證的API只需要做一次，不用每個請求都要丟到API做驗證後才能做下一步，各功能(伺服器)只要有secret-key即可解密

### 請求request中要包含的內容
適用於所有要跟後端、API發送的請求:
- JWT雙Token (Silent Refresh)
- 須包含第一個JWT token做身分認證(Access token)
- 須包含第二個JWT token可以更新Access token (Refresh token)，可以預防CSRF攻擊
- 須包含reCAPTCHA驗證

![image](https://hackmd.io/_uploads/rymJ2FEllg.png)


實作細節:
- Access token 要存在 memory防止CSRF攻擊
- Refresh Token 要存在cookie(屬性Secure, HttpOnly)防止XSS攻擊
- 實作上驗證要做的事情是，Access token會送到後端做解密，如果解密成功且尚未過期的話，進行下一步動作
- 如果Access token過期的話則需要將使用者導向重新申請Access token的API(/api/refresh)，如果Refresh Token解密成功且尚未過期的話，則回傳一個Access token回去
- 如果Refresh Token過期的話則導回登入頁面，讓使用者重新登入
- 這樣做的好處是不用處理session共享的問題

### 密碼從前端傳到後端 到資料庫的流程

**(login API)在登入的情況下:**
1. 使用者會在一個登入頁面輸入密碼登入，前端會將密碼明文傳到登入認證的API(api/login) (HTTPS會加密封包，就已經足夠安全了)
2. 後端拿到密碼後先在應用層做hash，然後去資料庫裡面查詢是否有該使用者，並回傳結果
3. 如果有的話將JWT的欄位用secret-key進行加密 (這裡的JWT須至少包含uuid、有效日期，其他的話官方有給[建議欄位](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1) ，或者可以[看別人寫的中文](https://medium.com/企鵝也懂程式設計/jwt-json-web-token-原理介紹-74abfafad7ba) )
4. 將Refresh Token回傳給使用者並且後端自動將使用者導向至重新申請Access token的API(/api/refresh)
5. 如果Refresh Token解密成功且尚未過期的話，則回傳一個Access token回去，並將使用者導向至主頁

:::info
補充說明:
- 在應用層做hash指的是，假如今天我的後端語言是python，我直接使用python做hash，然後把hash的結果在寫進資料庫，在做密碼驗證時也同樣如此。
- 因為資料庫並不是為了做hash的，應用層做hash會比在SQL中做得更快且順帶節省SQL的效能
:::


**(other service)使用者在登入後的情況下:**

1. 使用者訪問網頁時會將Access token傳到後端
2. 後端使用secret-key進行解密，如果解密成功且尚未過期的話，則繼續進行後續功能
3. 如果Access token過期的話，後端則需要將使用者重新導向至重新申請Access token的API(/api/refresh)
4. 如果Refresh Token解密成功且尚未過期的話，則回傳一個Access token回去，並將使用者重新導向至該功能頁面

