驗證碼(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自動區分計算機[1]和人類的圖靈測試[2])的縮寫,是一種區分用戶是計算機還是人的公共全自動程序[3]。可以防止:惡意破解密碼、刷票[4]、論壇灌水,有效防止某個黑客對某一個特定注冊用戶用特定程序暴力破解方式進行不斷的登陸嘗試,實際上用驗證碼是現在很多網站通行的方式,我們利用比較簡易的方式實現了這個功能。這個問題可以由計算機生成并評判,但是必須只有人類才能解答。由于計算機無法解答CAPTCHA的問題,所以回答出問題的用戶就可以被認為是人類。
傳統網站驗證碼工作機制
- 客戶端請求服務器獲取驗證碼圖片
- 服務器生成隨機串(驗證碼值)寫入Session,并將驗證碼值寫入到圖片中返回給客戶端
- 客戶端輸入圖片上的字符串提交給服務器驗證
- 服務器比對客戶端提交的字符串值和 Session 中是否匹配,如果匹配則通過驗證
由于服務器生成的驗證碼值從始至終均未返回給客戶端,因此,客戶端只能從圖片中識別驗證碼字符串,從而保證人機校驗邏輯。
Go的HTTP驗證碼
思路
Go 語言的 HTTP 服務器默認不支持 Session,因此驗證碼值需要換個思路存儲,以下是不使用 Session 的邏輯
- 客戶端請求服務器獲取驗證碼ID
- 服務器生成驗證碼 ID,并生成驗證碼值,將 ID 和值的映射關系記錄到內存或緩存,并將 ID 返回給客戶端
- 客戶端根據返回的 ID 請求服務器獲取驗證碼圖片
- 服務器獲取到驗證碼 ID,從內存或緩存中取出驗證碼值,將該值寫入圖片并將圖片返回給客戶端
- 客戶端提交驗證碼 ID(第1步獲得)和驗證碼值給服務器驗證
- 服務器獲取驗證碼 ID,從內存或緩存中取出驗證碼值與客戶端提交的驗證碼值比對
示例
- 安裝驗證碼依賴
go get -u 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。
本文作者:xialeistudio
原文鏈接:https://segmentfault.com/a/1190000023703468
參考資料
[1]
計算機: https://baike.baidu.com/item/計算機
[2]
圖靈測試: https://baike.baidu.com/item/圖靈測試
[3]
程序: https://baike.baidu.com/item/程序/71525
[4]
刷票: https://baike.baidu.com/item/刷票/6540942