Go 驗證表單的輸入

2022-05-13 17:49 更新

開發(fā)Web的一個原則就是,不能信任用戶輸入的任何信息,所以驗證和過濾用戶的輸入信息就變得非常重要,我們經(jīng)常會在微博、新聞中聽到某某網(wǎng)站被入侵了,存在什么漏洞,這些大多是因為網(wǎng)站對于用戶輸入的信息沒有做嚴(yán)格的驗證引起的,所以為了編寫出安全可靠的Web程序,驗證表單輸入的意義重大。

我們平常編寫Web應(yīng)用主要有兩方面的數(shù)據(jù)驗證,一個是在頁面端的js驗證(目前在這方面有很多的插件庫,比如ValidationJS插件),一個是在服務(wù)器端的驗證,我們這小節(jié)講解的是如何在服務(wù)器端驗證。

必填字段

你想要確保從一個表單元素中得到一個值,例如前面小節(jié)里面的用戶名,我們?nèi)绾翁幚砟兀縂o有一個內(nèi)置函數(shù)len可以獲取字符串的長度,這樣我們就可以通過len來獲取數(shù)據(jù)的長度,例如:

if len(r.Form["username"][0])==0{
    //為空的處理
}

r.Form對不同類型的表單元素的留空有不同的處理, 對于空文本框、空文本區(qū)域以及文件上傳,元素的值為空值,而如果是未選中的復(fù)選框和單選按鈕,則根本不會在r.Form中產(chǎn)生相應(yīng)條目,如果我們用上面例子中的方式去獲取數(shù)據(jù)時程序就會報錯。所以我們需要通過r.Form.Get()來獲取值,因為如果字段不存在,通過該方式獲取的是空值。但是通過r.Form.Get()只能獲取單個的值,如果是map的值,必須通過上面的方式來獲取。

數(shù)字

你想要確保一個表單輸入框中獲取的只能是數(shù)字,例如,你想通過表單獲取某個人的具體年齡是50歲還是10歲,而不是像“一把年紀(jì)了”或“年輕著呢”這種描述

如果我們是判斷正整數(shù),那么我們先轉(zhuǎn)化成int類型,然后進(jìn)行處理

getint,err:=strconv.Atoi(r.Form.Get("age"))
if err!=nil{
    //數(shù)字轉(zhuǎn)化出錯了,那么可能就不是數(shù)字
}

//接下來就可以判斷這個數(shù)字的大小范圍了
if getint >100 {
    //太大了
}

還有一種方式就是正則匹配的方式

if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m {
    return false
}

對于性能要求很高的用戶來說,這是一個老生常談的問題了,他們認(rèn)為應(yīng)該盡量避免使用正則表達(dá)式,因為使用正則表達(dá)式的速度會比較慢。但是在目前機(jī)器性能那么強(qiáng)勁的情況下,對于這種簡單的正則表達(dá)式效率和類型轉(zhuǎn)換函數(shù)是沒有什么差別的。如果你對正則表達(dá)式很熟悉,而且你在其它語言中也在使用它,那么在Go里面使用正則表達(dá)式將是一個便利的方式。

Go實現(xiàn)的正則是RE2,所有的字符都是UTF-8編碼的。

中文

有時候我們想通過表單元素獲取一個用戶的中文名字,但是又為了保證獲取的是正確的中文,我們需要進(jìn)行驗證,而不是用戶隨便的一些輸入。對于中文我們目前有兩種方式來驗證,可以使用 unicode 包提供的 func Is(rangeTab *RangeTable, r rune) bool 來驗證,也可以使用正則方式來驗證,這里使用最簡單的正則方式,如下代碼所示

if m, _ := regexp.MatchString("^\\p{Han}+$", r.Form.Get("realname")); !m {
    return false
}

英文

我們期望通過表單元素獲取一個英文值,例如我們想知道一個用戶的英文名,應(yīng)該是astaxie,而不是asta謝。

我們可以很簡單的通過正則驗證數(shù)據(jù):

if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m {
    return false
}

電子郵件地址

你想知道用戶輸入的一個Email地址是否正確,通過如下這個方式可以驗證:

if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m {
    fmt.Println("no")
}else{
    fmt.Println("yes")
}

手機(jī)號碼

你想要判斷用戶輸入的手機(jī)號碼是否正確,通過正則也可以驗證:

if m, _ := regexp.MatchString(`^(1[3|4|5|8][0-9]\d{4,8})$`, r.Form.Get("mobile")); !m {
    return false
}

下拉菜單

如果我們想要判斷表單里面``元素生成的下拉菜單中是否有被選中的項目。有些時候黑客可能會偽造這個下拉菜單不存在的值發(fā)送給你,那么如何判斷這個值是否是我們預(yù)設(shè)的值呢?

我們的select可能是這樣的一些元素

<select name="fruit">
<option value="apple">apple</option>
<option value="pear">pear</option>
<option value="banane">banane</option>
</select>

那么我們可以這樣來驗證

slice:=[]string{"apple","pear","banane"}

for _, v := range slice {
    if v == r.Form.Get("fruit") {
        return true
    }
}
return false

單選按鈕

如果我們想要判斷radio按鈕是否有一個被選中了,我們頁面的輸出可能就是一個男、女性別的選擇,但是也可能一個15歲大的無聊小孩,一手拿著http協(xié)議的書,另一只手通過telnet客戶端向你的程序在發(fā)送請求呢,你設(shè)定的性別男值是1,女是2,他給你發(fā)送一個3,你的程序會出現(xiàn)異常嗎?因此我們也需要像下拉菜單的判斷方式類似,判斷我們獲取的值是我們預(yù)設(shè)的值,而不是額外的值。

<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女

那我們也可以類似下拉菜單的做法一樣

slice:=[]int{1,2}

for _, v := range slice {
    if v == r.Form.Get("gender") {
        return true
    }
}
return false

復(fù)選框

有一項選擇興趣的復(fù)選框,你想確定用戶選中的和你提供給用戶選擇的是同一個類型的數(shù)據(jù)。

<input type="checkbox" name="interest" value="football">足球
<input type="checkbox" name="interest" value="basketball">籃球
<input type="checkbox" name="interest" value="tennis">網(wǎng)球

對于復(fù)選框我們的驗證和單選有點不一樣,因為接收到的數(shù)據(jù)是一個slice

slice:=[]string{"football","basketball","tennis"}
a:=Slice_diff(r.Form["interest"],slice)
if a == nil{
    return true
}

return false

上面這個函數(shù)Slice_diff包含在我開源的一個庫里面(操作slice和map的庫), https://github.com/astaxie/beeku

日期和時間

你想確定用戶填寫的日期或時間是否有效。例如 ,用戶在日程表中安排8月份的第45天開會,或者提供未來的某個時間作為生日。

Go里面提供了一個time的處理包,我們可以把用戶的輸入年月日轉(zhuǎn)化成相應(yīng)的時間,然后進(jìn)行邏輯判斷

t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go launched at %s\n", t.Local())

獲取time之后我們就可以進(jìn)行很多時間函數(shù)的操作。具體的判斷就根據(jù)自己的需求調(diào)整。

身份證號碼

如果我們想驗證表單輸入的是否是身份證,通過正則也可以方便的驗證,但是身份證有15位和18位,我們兩個都需要驗證

//驗證15位身份證,15位的是全部數(shù)字
if m, _ := regexp.MatchString(`^(\d{15})$`, r.Form.Get("usercard")); !m {
    return false
}

//驗證18位身份證,18位前17位為數(shù)字,最后一位是校驗位,可能為數(shù)字或字符X。
if m, _ := regexp.MatchString(`^(\d{17})([0-9]|X)$`, r.Form.Get("usercard")); !m {
    return false
}

上面列出了我們一些常用的服務(wù)器端的表單元素驗證,希望通過這個引導(dǎo)入門,能夠讓你對Go的數(shù)據(jù)驗證有所了解,特別是Go里面的正則處理。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號