4.2 Verification of inputs
One of the most important principles in web development is that you cannot trust anything from client side user forms. You have to validate all incoming data before use it. Many websites are affected by this problem, which is simple yet crucial.
There are two ways of verifying form data that are in common use. The first is JavaScript validation on the front-end, and the second is server validation on the back-end. In this section, we are going to talk about server side validation in web development.
Required fields
Sometimes we require that users input some fields but they fail to complete the field. For example in the previous section when we required a username. You can use the len
function to get the length of a field in order to ensure that users have entered something.
if len(r.Form["username"][0])==0{
// code for empty field
}
r.Form
treats different form element types differently when they are blank. For empty textboxes, text areas and file uploads, it returns an empty string; for radio buttons and check boxes, it doesn't even create the corresponding items. Instead, you will get errors if you try to access it. Therefore, it's safer to use r.Form.Get()
to get field values since it will always return empty if the value does not exist. On the other hand, r.Form.Get()
can only get one field value at a time, so you need to use r.Form
to get the map of values.
Numbers
Sometimes you require numbers rather than other text for the field value. For example, let's say that you require the age of a user in integer form only, i.e 50 or 10, instead of "old enough" or "young man". If we require a positive number, we can convert the value to the int
type first, then process it.
getint,err:=strconv.Atoi(r.Form.Get("age"))
if err!=nil{
// error occurs when convert to number, it may not a number
}
// check range of number
if getint >100 {
// too big
}
Another way to do this is by using regular expressions.
if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m {
return false
}
For high performance purposes, regular expressions are not efficient, however simple regular expressions are usually fast enough. If you are familiar with regular expressions, it's a very convenient way to verify data. Notice that Go uses RE2, so all UTF-8 characters are supported.
Chinese
Sometimes we need users to input their Chinese names and we have to verify that they all use Chinese rather than random characters. For Chinese verification, regular expressions are the only way.
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", r.Form.Get("realname")); !m {
return false
}
English letters
Sometimes we need users to input only English letters. For example, we require someone's English name, like astaxie instead of asta谢. We can easily use regular expressions to perform our verification.
if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m {
return false
}
E-mail address
If you want to know whether users have entered valid E-mail addresses, you can use the following regular expression:
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")
}
Drop down list
Let's say we require an item from our drop down list, but instead we get a value fabricated by hackers. How do we prevent this from happening?
Suppose we have the following <select>
:
<select name="fruit">
<option value="apple">apple</option>
<option value="pear">pear</option>
<option value="banana">banana</option>
</select>
We can use the following strategy to sanitize our input:
slice:=[]string{"apple","pear","banana"}
for _, v := range slice {
if v == r.Form.Get("fruit") {
return true
}
}
return false
All the functions I've shown above are in my open source project for operating on slices and maps: https://github.com/astaxie/beeku
Radio buttons
If we want to know whether the user is male or female, we may use a radio button, returning 1 for male and 2 for female. However, some little kid who just read his first book on HTTP, decides to send to you a 3. Will your program throw an exception? As you can see, we need to use the same method as we did for our drop down list to make sure that only expected values are returned by our radio button.
<input type="radio" name="gender" value="1">Male
<input type="radio" name="gender" value="2">Female
And we use the following code to validate the input:
slice:=[]int{1,2}
for _, v := range slice {
if v == r.Form.Get("gender") {
return true
}
}
return false
Check boxes
Suppose there are some check boxes for user interests, and that you don't want extraneous values here either. You can validate these ase follows:
<input type="checkbox" name="interest" value="football">Football
<input type="checkbox" name="interest" value="basketball">Basketball
<input type="checkbox" name="interest" value="tennis">Tennis
In this case, the sanitization is a little bit different to validating the button and check box inputs since here we get a slice from the check boxes.
slice:=[]string{"football","basketball","tennis"}
a:=Slice_diff(r.Form["interest"],slice)
if a == nil{
return true
}
return false
Date and time
Suppose you want users to input valid dates or times. Go has the time
package for converting year, month and day to their corresponding times. After that, it's easy to check it.
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go launched at %s\n", t.Local())
After you have the time, you can use the time
package for more operations, depending on your needs.
In this section, we've discussed some common methods of validating form data on the server side. I hope that you now understand more about data validation in Go, especially how to use regular expressions to your advantage.
Links
- Directory
- Previous section: Process form inputs
- Next section: Cross site scripting