go web 預防跨站腳本的實現方式
一 點睛
現在的網站包含大量的動態內容以提高用戶體驗,比過去要復雜得多。所謂動態內容,就是根據用戶環境和需要,Web 應用程序能夠輸出相應的內容。動態站點會受到一種名為“跨站腳本攻擊”(Cross Site Scripting, 安全專傢們通常將其縮寫成 XSS)的威脅,而靜態站點則完全不受其影響。
攻擊者通常會在有漏洞的程序中插入 JavaScript、VBScript、 ActiveX 或 Flash 以欺騙用戶。一旦得手,他們可以盜取用戶帳戶信息,修改用戶設置,盜取或污染 cookie 和植入惡意廣告等。
對 XSS 最佳的防護應該結合以下兩種方式。
1 驗證所有輸入數據,有效檢測攻擊。
2 對所有輸出數據進行適當的處理,以防止任何已成功註入的腳本在瀏覽器端運行。
針對第2種方式,Go 是怎樣預防的呢?Go 的 html/template 包中帶有下面幾個函數可以幫助轉義。
func HTMLEscape(w io.Writer, b []byte) // 把 b 進行轉義之後寫到 w
func HTMLEscapeString(s string) string // 轉義 s 之後返回結果字符串
func HTMLEscaper(args …interface{}) string // 支持多個參數一起轉義,返回結果字符串
二 先看一個轉義的例子
1 代碼
package main import ( "fmt" "html/template" "log" "net/http" ) // 登錄邏輯 func login(w http.ResponseWriter, r *http.Request) { fmt.Println("method:", r.Method) // 獲取請求的方法 if r.Method == "GET" { t, _ := template.ParseFiles("src\\goweb\\demo3\\login.html") // 解析模板 t.Execute(w, nil) // 渲染模板,並發送給前端 } else { // 請求的是登陸數據,那麼執行登陸的邏輯判斷 // 解析表單 r.ParseForm() fmt.Println("username:", r.Form["username"]) fmt.Println("password:", r.Form["password"]) template.HTMLEscape(w, []byte(r.Form.Get("username"))) //輸出到客戶端 } } func main() { http.HandleFunc("/login", login) // 設置訪問的路由 err := http.ListenAndServe(":9090", nil) // 設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } }
2 測試
如果在瀏覽器輸入的 username 是 <script>alert()</script>,在瀏覽器上將看到下面內容。
3 說明
Go 的 html/template 包默認幫忙過濾瞭 html 標簽,將其進行瞭轉義。
4 問題引出
如果要正常輸出<script>alert()</script>,怎樣處理呢?text/template 可以幫忙進行處理。
三 使用 text/template 進行處理
1 代碼
package main import ( "log" "net/http" "text/template" ) // 轉義測試 func escape(w http.ResponseWriter, r *http.Request) { // 正常顯示 t, _ := template.New("foo").Parse(`{{define "T"}}Hello1, {{.}}!{{end}}`) t.ExecuteTemplate(w, "T", "<script>alert('you have been pwned')</script>") } func main() { http.HandleFunc("/escape", escape) // 設置轉義 err := http.ListenAndServe(":9090", nil) // 設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } }
2 測試
3 說明
當使用 text/template 這個包時,可以正常顯示。
四 使用 html/template 進行處理
1 代碼
package main import ( "html/template" "log" "net/http" ) // 轉義測試 func escape(w http.ResponseWriter, r *http.Request) { // 轉義顯示 t, _ := template.New("foo").Parse(`{{define "T"}}Hello1, {{.}}!{{end}}`) t.ExecuteTemplate(w, "T", "<script>alert('you have been pwned')</script>") // 正常顯示 t, _ = template.New("foo").Parse(`{{define "T"}}Hello2, {{.}}!{{end}}`) t.ExecuteTemplate(w, "T", template.HTML("<script>alert('you have been pwned')</script>")) } func main() { http.HandleFunc("/escape", escape) // 設置轉義 err := http.ListenAndServe(":9090", nil) // 設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } }
2 測試結果
3 說明
當使用 html/template 這個包時,如果使用 template.HTML 函數,也可以正常顯示,不使用 template.HTML 函數,轉義顯示。
以上就是go web 預防跨站腳本的詳細內容,更多關於go web 預防跨站的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- golang 實現Location跳轉方式
- Go語言實現文件上傳
- Golang實現HTTP編程請求和響應
- Golang使用WebSocket通信的實現
- go 原生http web 服務跨域restful api的寫法介紹