驗證碼(CAPTCHA)是「Completely Automated Public Turing test to tell Computers and Humans Apart」(全自動區分電腦和人類的圖靈測試)的縮寫,是一種區分使用者是電腦還是人的公共全自動程式。可以防止:惡意破解密碼、刷票、論壇灌水,有效防止某個駭客對某一個特定註冊用戶用特定程序暴力破解方式進行不斷的登陸嘗試,實際上用驗證碼是現在很多網站通行的方式,我們利用比較簡易的方式實現了這個功能。這個問題可以由電腦產生並評判,但是必須只有人類才能解答。由於電腦無法解答CAPTCHA的問題,所以回答出問題的使用者就可以被認為是人類。
傳統網站驗證碼工作機制
- 客戶端請求伺服器取得驗證碼圖片
- #伺服器產生隨機字串(驗證碼值)寫入Session,並將驗證碼值寫入到圖片中傳回給客戶端
- 客戶端輸入圖片上的字串提交給伺服器驗證
- 伺服器比對客戶端提交的字符串值和Session 中是否匹配,如果匹配則通過驗證
由於伺服器產生的驗證碼值從始至終均未返回給客戶端,因此,客戶端只能從圖片中識別驗證碼字串,從而保證人機校驗邏輯。
Go的HTTP驗證碼
想法
Go 語言的HTTP 伺服器預設不支援Session,因此驗證碼值需要換個思路存儲,以下是不使用Session 的邏輯
- 客戶端請求伺服器取得驗證碼ID
- #伺服器產生驗證碼ID,並產生驗證碼值,將ID 和值的對應關係記錄到記憶體或緩存,並將ID 傳回給客戶端
- 客戶端根據傳回的ID 請求伺服器取得驗證碼圖片
- 伺服器取得到驗證碼ID,從記憶體或快取中取出驗證碼值,將該值寫入圖片並將圖片傳回給客戶端
- 客戶端提交驗證碼ID(第1步驟取得)和驗證碼值給伺服器驗證
- 伺服器取得驗證碼ID,從記憶體或快取中取出驗證碼值與客戶端提交的驗證碼值比對
範例
- 安裝驗證碼依賴
github.com/dchest/captcha
登入後複製
- 程式碼實作
package main import ( "fmt" "github.com/dchest/captcha" "log" "net/http" ) func main() { // 获取验证码 ID http.HandleFunc("/captcha/generate", func(w http.ResponseWriter, r *http.Request) { id := captcha.NewLen(6) if _, err := fmt.Fprint(w, id); err != nil { log.Println("generate captcha error", err) } }) // 获取验证码图片 http.HandleFunc("/captcha/image", func(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") if id == "" { http.Error(w, "Bad Request", http.StatusBadRequest) return } w.Header().Set("Content-Type", "image/png") if err := captcha.WriteImage(w, id, 120, 80); err != nil { log.Println("show captcha error", err) } }) // 业务处理 http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) { if err := r.ParseForm(); err != nil { log.Println("parseForm error", err) http.Error(w, "Internal Error", http.StatusInternalServerError) return } // 获取验证码 ID 和验证码值 id := r.FormValue("id") value := r.FormValue("value") // 比对提交的验证码值和内存中的验证码值 if captcha.VerifyString(id, value) { fmt.Fprint(w, "ok") } else { fmt.Fprint(w, "mismatch") } }) log.Fatal(http.ListenAndServe(":8080", nil)) }
登入後複製
-
執行
- 訪問/captcha/generate取得驗證碼ID
- #存取/captcha/image?id=驗證碼ID
- 存取/login,並輸入第一步的驗證碼ID 和第二步驟的驗證碼值即可查看驗證結果
專案地址
https://github.com/xialeistudio/go-http-captcha-example