Одним из наиболее важных правил веб-разработки является то, что нельзя доверять никаким данным, поступившим из пользовательских форм. Вы должны проверять все входящие данные перед тем, как их использовать. Множество веб-сайтов было затронуто этой очень серьезной проблемой.
Существует два наиболее часто используемых способа проверить данные. Один - это проверка средствами Javascript на стороне браузера, а второй - проверка на стороне сервера. В этом разделе мы поговорим о проверке данных средствами сервера.
Иногда требуется, чтобы пользователь заполнил определенные поля, но он этого не делает; например, в предыдущем разделе, когда нам требовалось имя пользователя. Чтобы получить длину строки в поле и быть уверенными, что пользователь заполнил его, мы можем использовать функцию len
:
if len(r.Form["username"][0])==0{
// код, выполняемый, если поле оказалось пустым
}
r.Form
обрабатывает незаполненные поля различными способами в зависимости от их типа. Для пустых текстовых полей, текстовых областей и загружаемых файлов она возвращает пустую строку; для радиокнопок и чекбоксов просто не создаются соответствующие значения. Вместо этого при попытке доступа к ним Вы получите ошибку. Поэтому для получения значений безопаснее использовать r.Form.Get()
, так как эта команда всегда возвращает пустые значения. С другой стороны, r.Form.Get()
может получить только одно значение за один вызов, поэтому для того, чтобы получить карту значений, нужно использовать r.Form
.
Иногда значениями поля могут быть только числа. Например, Вам нужно получить возраст пользователя в целочисленном виде, т.е. 50 или 10, вместо "довольно взрослый" или "молодой человек". Если нам нужно положительное число, мы можем сначала конвертировать значение поля в тип int
, а затем уже работать с ним:
getint,err:=strconv.Atoi(r.Form.Get("age"))
if err!=nil{
// если значение не конвертируется в целое число, то было введено не целое число
}
// проверяем диапазон значений
if getint >100 {
// слишком много
}
Другой способ проверки - это регулярные выражения:
if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m {
return false
}
Хотя регулярные выражения неэффективны в плане производительности, простые регулярные выражения довольно быстры. Если Вы с ними знакомы, то их использование может быть довольно-таки удобным способом проверить данные. Имейте в виду, что Go использует RE2, что означает, что при работе с регулярными выражениями в Go поддерживаются все символы UTF-8.
Иногда нам нужно от пользователей, чтобы они вводили свои китайские имена, и нам нужно проверять, что они используют китайские, а не случайные символы. Для осуществления этой задачи регулярные выражения - единственный способ.
if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", r.Form.Get("realname")); !m {
return false
}
Иногда нужно, чтобы пользователь вводил только английские буквы. Предположим, нам нужно, чтобы пользователь вводил свое имя по-английски, например, astaxie, а не asta谢. Чтобы легко осуществить такую проверку, можно воспользоваться регулярными выражениями:
if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m {
return false
}
( Прим. переводчика на русский язык - для русского языка регулярка в данном случае будет выглядеть как "[А-аЯ-яЁё]+$" )
Если Вам нужно узнать, ввел ли пользователь корректный адрес E-mail, можно использовать следующее регулярное выражение:
if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m {
fmt.Println("нет")
}else{
fmt.Println("да")
}
Допустим, нам нужно получить значение из выпадающего списка, но вместо этого мы получаем значение, сфабрикованное хакерами. Как предотвратить такой случай?
Предположим, у нас есть следующий <select>
:
<select name="fruit">
<option value="apple">Яблоко</option>
<option value="pear">Груша</option>
<option value="banana">Банан</option>
</select>
Для очистки вводимых данных можно использовать следующую стратегию:
slice:=[]string{"apple","pear","banana"}
for _, v := range slice {
if v == r.Form.Get("fruit") {
return true
}
}
return false
Все функции, котоые я показал выше, есть в моем open source проекте для оперирования срезами и картами: https://github.com/astaxie/beeku
Если нам нужно узнать пол пользователя, мы можем воспользоваться радиокнопками, которые будут возвращать "1" для мужчины и "2" для женщины. Однако, какой-нибудь маленький ребенок, прочитав свою первую книгу по HTTP, захочет послать Вам "3". Будет ли готова Ваша программа обработать это исключение? Как Вы увидите, для того, чтобы узнать, послано ли нам значение из нужного диапазона, мы используем тот же метод, что и для выпадающих списков:
<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
Предположим у нас имеются несколько чекбоксов для получения информации об интересах пользователя, и мы не хотим, чтобы они возвращали непредусмотренные значения.
<input type="checkbox" name="interest" value="football">Футбол
<input type="checkbox" name="interest" value="basketball">Баскетбол
<input type="checkbox" name="interest" value="tennis">Теннис
В этом случае проверка входящих данных немного отличается от того, что было с радиокнопками, так как чекбокс возвращает срез значений:
slice:=[]string{"football","basketball","tennis"}
a:=Slice_diff(r.Form["interest"],slice)
if a == nil{
return true
}
return false
Предположим, Вы хотите, чтобы пользователи вводили дату и время правильно. Для конвертирования лет, месяцев и дней в соответствующие значения типа 'time' в Go есть пакет time
. С его помощью можно легко проверить введенную дату.
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
fmt.Printf("Go запущен в %s\n", t.Local())
После того, как нам стало известно время, мы можем использовать пакет time
для решения еще большего числа задач в зависимости от наших потребностей.
В этом разделе мы обсудили несколько общих способов проверки данных пользовательских форм на стороне сервера. Я надеюсь, что теперь Вы больше понимаете о проверке данных в Go, особенно о том, как использовать регулярные выражения.
- Содержание
- Предыдущий раздел: Работа с формами
- Следующий раздел: Межсайтовый скриптинг