Go CSRF / XSRF 令牌的目的與表單保護 以及標準套件的預設令牌有效期
大家好,我是無能。
我個人製作並使用的線上儲存服務
GitHub - haturatu/puremania: No security, very fast, web UI self-hosted online storage
,但如果想在前端加上認證,所以我製作了一個認證代理伺服器。
GitHub - haturatu/auth-proxy: An authentication proxy server and frontend for a website without built-in authentication. JavaScript is supported, but it can also work without JS if using PHP-FPM. The backend is written in Go.
實際上,這幾乎都是 Gemini 的功勞...
只代理通過認證的請求。
管理員用戶可以發行用於 API 端點的 Bearer 令牌,並使用該令牌來通過請求。然而,在這種情況下,有些 API 端點也需要從前端會話訪問,所以實際上無論是 Cookie 還是 Bearer 令牌都可以通過。
如果只保護 API 端點,將 Web 登入等前端隔離在私人網路中,只公開 API 端點,那麼用戶創建可以在私人網路中進行,並使用該用戶發放 API 令牌和 API 代理實際上是可行的。(請不要說「用 API Gateway 類的開源軟體不就好了嗎」)
實際上,這樣一來,Cookie 和令牌的雙重暴力破解實際上是可能的,但嘛...
因此,接下來是關於表單安全性,為了登入時的網頁前端安全。
如果強制載入 JS,大部分問題都可以解決,但只依賴 JS 不是很無聊嗎?所以我們決定使用 JS 以外的方法來提高表單的安全性。
CSRF / XSRF 令牌
這將是這次的焦點,但這到底是什麼呢?
簡單來說,就是驗證伺服器端和客戶端請求是否確實從我這裡發出並頒發,並且如果該令牌在有效期內則允許。
例如
<input type="hidden" name="xsrf_token" value="BeftikzaR8Oe6npnqXYC7WtBhuo:1760376550660">
這樣的令牌會嵌入到前端 HTML 中。這個 value 由伺服器端的秘密金鑰簽名。因此伺服器端就知道這是從我的伺服器端頒發的!1760376550660 只是一串 UNIX 時間的字元,那麼它在當前時間有什麼用呢?
xsrftoken package - golang.org/x/net/xsrftoken - Go Packages
func ValidFor(token, key, userID, actionID string, timeout time.Duration) bool
用於上述的期限設定。
實際上,加上time套件後會像這樣:
if !xsrftoken.ValidFor(clientToken, string(xsrfSecret), sessionID, r.URL.Path, 15*time.Minute) {
如果沒有提供這個參數,預設是 24 小時,這相當寬鬆,但我想這只是作為 XSRF Token 應有的形式提供,即只需驗證令牌是由伺服器頒發的。
CSRF 和 XSRF 的區別是什麼啊!
實際上,似乎沒有太大區別。
目的都是防止跨站攻擊。
對於 CSRF
GitHub - gorilla/csrf: Package gorilla/csrf provides Cross Site Request Forgery (CSRF) prevention middleware for Go web applications & services 🔒
有這個函式庫,我偶然看到了這裡。
gorilla/csrf CSRF 脆弱性演示
改進 gorilla/csrf 實作的一種方法是將表單中使用的隨機值替換為與用戶 ID 綁定的加密令牌。這可以防止攻擊者將自己的 CSRF 令牌和 Cookie 值替換為目標的,因為攻擊者的 CSRF 令牌對應於不同的 ID。實際上,這種方法已在一個函式庫中實作,該函式庫使用 x/net/xsrftokenHMAC 來驗證用戶 ID、可選的表單動作和有效期。
所以我認為它應該是標準函式庫的一部分
xsrftoken/xsrf.go
查看原始碼後大吃一驚,連同註釋也才 100 行!雖然有點擔心還在使用 SHA1,但總有一天會升級吧。
總之,如果標準函式庫如此簡單就能達到目的,那麼這就足夠了;如果要進行SameSite驗證,或許應該使用gorilla/csrf。
標準函式庫的注意事項
正如前面提到的,預設令牌的有效期是24H。
在實際操作中,這個令牌期限可能會被濫用,所以縮短時間可能更好。假設這個令牌是用於發送填寫表單之前的請求,那麼 24 小時的有效期,如果沒有其他安全措施,同一個令牌可以多次通過請求,因此使用無限curl重複使用同一個令牌向表單發送請求,進行暴力破解並非不可能。