68 lines
5.3 KiB
Markdown
68 lines
5.3 KiB
Markdown
# 4.3 Межсайтовый скриптинг
|
||
|
||
Для совершенствования взаимодействия с пользователем современные сайты содержат все больше динамического контента, что означает, что мы должны предоставлять информацию динамически, в зависимости от поведения каждого пользователя. К сожалению, существует такое явление как "межсайтовый скриптинг" (известный как "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>!
|
||
|
||
## Ссылки
|
||
|
||
- [Содержание](preface.md)
|
||
- Предыдущий раздел: [Проверка введенных данных](04.2.md)
|
||
- Следующий раздел: [Дублирование отправки](04.4.md)
|