Files
build-web-application-with-…/zh-tw/04.4.md
2019-02-26 01:40:54 +08:00

61 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 4.4 防止多次遞交表單
不知道你是否曾經看到過一個論壇或者部落格,在一個帖子或者文章後面出現多條重複的記錄,這些大多數是因為使用者重複遞交了留言的表單引起的。由於種種原因,使用者經常會重複遞交表單。通常這只是滑鼠的誤操作,如雙擊了遞交按鈕,也可能是為了編輯或者再次核對填寫過的資訊,點選了瀏覽器的後退按鈕,然後又再次點選了遞交按鈕而不是瀏覽器的前進按鈕。當然,也可能是故意的——比如,在某項線上調查或者博彩活動中重複投票。那我們如何有效的防止使用者多次遞交相同的表單呢?
解決方案是在表單中新增一個帶有唯一值的隱藏欄位。在驗證表單時先檢查帶有該唯一值的表單是否已經遞交過了。如果是拒絕再次遞交如果不是則處理表單進行邏輯處理。另外如果是採用了Ajax模式遞交表單的話當表單遞交後透過javascript來禁用表單的遞交按鈕。
我繼續拿4.2小節的例子優化:
```html
<input type="checkbox" name="interest" value="football">足球
<input type="checkbox" name="interest" value="basketball">籃球
<input type="checkbox" name="interest" value="tennis">網球
使用者名稱:<input type="text" name="username">
密碼:<input type="password" name="password">
<input type="hidden" name="token" value="{{.}}">
<input type="submit" value="登陸">
```
我們在模版裡面增加了一個隱藏欄位`token`這個值我們透過MD5(時間戳)來取得唯一值,然後我們把這個值儲存到伺服器端(session來控制我們將在第六章講解如何儲存),以方便表單提交時比對判定。
```Go
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) //取得請求的方法
if r.Method == "GET" {
crutime := time.Now().Unix()
h := md5.New()
io.WriteString(h, strconv.FormatInt(crutime, 10))
token := fmt.Sprintf("%x", h.Sum(nil))
t, _ := template.ParseFiles("login.gtpl")
t.Execute(w, token)
} else {
//請求的是登陸資料,那麼執行登陸的邏輯判斷
r.ParseForm()
token := r.Form.Get("token")
if token != "" {
//驗證token的合法性
} else {
//不存在token報錯
}
fmt.Println("username length:", len(r.Form["username"][0]))
fmt.Println("username:", template.HTMLEscapeString(r.Form.Get("username"))) //輸出到伺服器端
fmt.Println("password:", template.HTMLEscapeString(r.Form.Get("password")))
template.HTMLEscape(w, []byte(r.Form.Get("username"))) //輸出到客戶端
}
}
```
上面的程式碼輸出到頁面的原始碼如下:
![](images/4.4.token.png?raw=true)
圖4.4 增加token之後在客戶端輸出的原始碼資訊
我們看到token已經有輸出值你可以不斷的重新整理可以看到這個值在不斷的變化。這樣就保證了每次顯示form表單的時候都是唯一的使用者遞交的表單保持了唯一性。
我們的解決方案可以防止非惡意的攻擊,並能使惡意使用者暫時不知所措,然後,它卻不能排除所有的欺騙性的動機,對此類別情況還需要更復雜的工作。
## links
* [目錄](<preface.md>)
* 上一節: [預防跨站指令碼](<04.3.md>)
* 下一節: [處理檔案上傳](<04.5.md>)