Для совершенствования взаимодействия с пользователем современные сайты содержат все больше динамического контента, что означает, что мы должны предоставлять информацию динамически в зависимости от поведения каждого пользователя. К сожалению, существует такое явление как "межсайтовый скриптинг" (известный как "XSS"), с помощью которого осуществляются постоянные атаки на динамические сайты, в то время как сайты со статическим содержимым этим атакам не подвержены.
Злоумышленники посылают на сайты, подверженные межсайтовому скриптингу, скрипты на JavaScript, VBScript, ActiveX или Flash. Если скрипт удачно вторгся на сайт, пользовательская информация может быть похищена, а сайт наполнен спамом. Злоумышленники могут также изменить настройки пользователя на те, которые захотят.
Если Вы хотите предотвратить этот тип атаки, Вам нужно комбинировать два следующих подхода:
- Проверка всех данных, идущих от пользователя, о чем мы поговорили в предыдущей главе.
- Обработка всех данных, посылаемых клиенту, для того, чтобы предотвратить запуск опасных скриптов в браузере.
Итак, как нам осуществить эти два пункта в Go? К счастью, пакет html/template
имеет в своем распоряжении несколько полезных функций, чтобы обезопасить данные:
func HTMLEscape(w io.Writer, b []byte)
отправляет в w версию b с заменой потенциально опасных символов на их escape-последовательности.func HTMLEscapeString(s string) string
возвращает версию s с заменой потенциально опасных символов на их escape-последовательности.func HTMLEscaper(args ...interface{}) string
формирует строку из множества аргументов с заменой потенциально опасных символов на escape-последовательности.
Давайте изменим пример из раздела 4.1:
fmt.Println("Имя пользователя:", template.HTMLEscapeString(r.Form.Get("username"))) // печатает на стороне сервера
fmt.Println("Пароль:", template.HTMLEscapeString(r.Form.Get("password")))
template.HTMLEscape(w, []byte(r.Form.Get("username"))) // отправляет клиенту
Если кто-то попробует ввести в поле для ввода имени пользователя <script>alert()</script>
, мы увидим следующую картину в браузере:
Рисунок 4.3 JavaScript после обработки escape-последовательностью
Функции пакета html/template
помогут Вам заменить все теги HTML на их безопасные аналоги. Но что, если Вам нужно передать в браузер <script>alert()</script>
? В этом случае нужно использовать пакет text/template
:
import "text/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Привет, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('Вы попались!')</script>")
Вывод:
Привет, <script>alert('Вы попались!')</script>!
Или можно использовать тип template.HTML
. Содержимое переменной типа template.HTML
не изменяется с учетом escape-последовательностей:
import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Привет, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", template.HTML("<script>alert('Вы попались!')</script>"))
Вывод:
Привет, <script>alert('Вы попались!')</script>!
Еще один пример эскейпинга:
import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Привет, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('Вы попались!')</script>")
Вывод:
Привет, <script>alert('Вы попались!')</script>!
- Содержание
- Предыдущий раздел: Проверка введенных данных
- Следующий раздел: Дублирование отправки