Files
2019-06-22 23:41:28 +08:00

73 lines
3.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 4.3 預防跨站指令碼
現在的網站包含大量的動態內容以提高使用者體驗比過去要複雜得多。所謂動態內容就是根據使用者環境和需要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>`,那麼我們可以在瀏覽器上面看到輸出如下所示:
![](images/4.3.escape.png)
圖 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
* [目錄](<preface.md>)
* 上一節:[驗證的輸入](<04.2.md>)
* 下一節:[防止多次提交表單](<04.4.md>)