# 預防跨站指令碼

現在的網站包含大量的動態內容以提高使用者體驗，比過去要複雜得多。所謂動態內容，就是根據使用者環境和需要，Web 應用程式能夠輸出相應的內容。動態站點會受到一種名為“跨站指令碼攻擊”（Cross Site Scripting, 安全專家們通常將其縮寫成 XSS）的威脅，而靜態站點則完全不受其影響。

攻擊者通常會在有漏洞的程式中插入 JavaScript、VBScript、 ActiveX 或 Flash 以欺騙使用者。一旦得手，他們可以盜取使用者帳戶資訊，修改使用者設定，盜取/汙染 cookie 和植入惡意廣告等。

對 XSS 最佳的防護應該結合以下兩種方法：一是驗證所有輸入資料，有效檢測攻擊(這個我們前面小節已經有過介紹);另一個是對所有輸出資料進行適當的處理，以防止任何已成功注入的指令碼在瀏覽器端執行。

那麼 Go 裡面是怎麼做這個有效防護的呢？Go 的 html/template 裡面帶有下面幾個函式可以幫你轉義

* func HTMLEscape(w io.Writer, b \[]byte)  //把 b 進行轉義之後寫到 w
* func HTMLEscapeString(s string) string  //轉義 s 之後回傳結果字串
* func HTMLEscaper(args ...interface{}) string //支援多個參數一起轉義，回傳結果字串

我們看 4.1 小節的例子

```go
fmt.Println("username:", template.HTMLEscapeString(r.Form.Get("username"))) //輸出到伺服器端
fmt.Println("password:", template.HTMLEscapeString(r.Form.Get("password")))
template.HTMLEscape(w, []byte(r.Form.Get("username"))) //輸出到客戶端
```

如果我們輸入的 username 是`<script>alert()</script>`，那麼我們可以在瀏覽器上面看到輸出如下所示：

![](/files/-M6Eeu9CgaWAS3ipHWYY)

圖 4.3 Javascript 過濾之後的輸出

Go 的 html/template 套件預設幫你過濾了 html 標籤，但是有時候你只想要輸出這個`<script>alert()</script>`看起來正常的資訊，該怎麼處理？請使用 text/template。請看下面的例子：

```go
import "text/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
```

輸出

```
Hello, <script>alert('you have been pwned')</script>!
```

或者使用 template.HTML 型別

```go
import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", template.HTML("<script>alert('you have been pwned')</script>"))
```

輸出

```
Hello, <script>alert('you have been pwned')</script>!
```

轉換成`template.HTML`後，變數的內容也不會被轉義

轉義的例子：

```go
import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
```

轉義之後的輸出：

```
Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!
```

## links

* [目錄](https://github.com/doggy8088/build-web-application-with-golang-zhtw/tree/4cbbaa31bdfc3678915eb91f23db2f1bad554a20/preface.md)
* 上一節: [驗證的輸入](/build-web-application-with-golang-zhtw/04.0/04.2.md)
* 下一節: [防止多次提交表單](/build-web-application-with-golang-zhtw/04.0/04.4.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://willh.gitbook.io/build-web-application-with-golang-zhtw/04.0/04.3.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
