目錄
- 一 點(diǎn)睛
- 二 先看一個(gè)轉(zhuǎn)義的例子
- 三 使用 text/template 進(jìn)行處理
- 四 使用 html/template 進(jìn)行處理
一 點(diǎn)睛
現(xiàn)在的網(wǎng)站包含大量的動(dòng)態(tài)內(nèi)容以提高用戶體驗(yàn),比過去要復(fù)雜得多。所謂動(dòng)態(tài)內(nèi)容,就是根據(jù)用戶環(huán)境和需要,Web 應(yīng)用程序能夠輸出相應(yīng)的內(nèi)容。動(dòng)態(tài)站點(diǎn)會(huì)受到一種名為“跨站腳本攻擊”(Cross Site Scripting, 安全專家們通常將其縮寫成 XSS)的威脅,而靜態(tài)站點(diǎn)則完全不受其影響。
攻擊者通常會(huì)在有漏洞的程序中插入 JavaScript、VBScript、 ActiveX 或 Flash 以欺騙用戶。一旦得手,他們可以盜取用戶帳戶信息,修改用戶設(shè)置,盜取或污染 cookie 和植入惡意廣告等。
對(duì) XSS 最佳的防護(hù)應(yīng)該結(jié)合以下兩種方式。
1 驗(yàn)證所有輸入數(shù)據(jù),有效檢測(cè)攻擊。
2 對(duì)所有輸出數(shù)據(jù)進(jìn)行適當(dāng)?shù)奶幚?,以防止任何已成功注入的腳本在瀏覽器端運(yùn)行。
針對(duì)第2種方式,Go 是怎樣預(yù)防的呢?Go 的 html/template 包中帶有下面幾個(gè)函數(shù)可以幫助轉(zhuǎn)義。
func HTMLEscape(w io.Writer, b []byte) // 把 b 進(jìn)行轉(zhuǎn)義之后寫到 w
func HTMLEscapeString(s string) string // 轉(zhuǎn)義 s 之后返回結(jié)果字符串
func HTMLEscaper(args ...interface{}) string // 支持多個(gè)參數(shù)一起轉(zhuǎn)義,返回結(jié)果字符串
二 先看一個(gè)轉(zhuǎn)義的例子
1 代碼
package main
import (
"fmt"
"html/template"
"log"
"net/http"
)
// 登錄邏輯
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("method:", r.Method) // 獲取請(qǐng)求的方法
if r.Method == "GET" {
t, _ := template.ParseFiles("src\\goweb\\demo3\\login.html") // 解析模板
t.Execute(w, nil) // 渲染模板,并發(fā)送給前端
} else {
// 請(qǐng)求的是登陸數(shù)據(jù),那么執(zhí)行登陸的邏輯判斷
// 解析表單
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) // 設(shè)置訪問的路由
err := http.ListenAndServe(":9090", nil) // 設(shè)置監(jiān)聽的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
2 測(cè)試
如果在瀏覽器輸入的 username 是 script>alert()/script>,在瀏覽器上將看到下面內(nèi)容。
![](/d/20211017/facf39c9998b5b03c4f10d4baa8d880c.gif)
3 說(shuō)明
Go 的 html/template 包默認(rèn)幫忙過濾了 html 標(biāo)簽,將其進(jìn)行了轉(zhuǎn)義。
4 問題引出
如果要正常輸出script>alert()/script>,怎樣處理呢?text/template 可以幫忙進(jìn)行處理。
三 使用 text/template 進(jìn)行處理
1 代碼
package main
import (
"log"
"net/http"
"text/template"
)
// 轉(zhuǎn)義測(cè)試
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) // 設(shè)置轉(zhuǎn)義
err := http.ListenAndServe(":9090", nil) // 設(shè)置監(jiān)聽的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
2 測(cè)試
![](/d/20211017/8e70aa811e6afcf696557890383a90f1.gif)
3 說(shuō)明
當(dāng)使用 text/template 這個(gè)包時(shí),可以正常顯示。
四 使用 html/template 進(jìn)行處理
1 代碼
package main
import (
"html/template"
"log"
"net/http"
)
// 轉(zhuǎn)義測(cè)試
func escape(w http.ResponseWriter, r *http.Request) {
// 轉(zhuǎn)義顯示
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) // 設(shè)置轉(zhuǎn)義
err := http.ListenAndServe(":9090", nil) // 設(shè)置監(jiān)聽的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
2 測(cè)試結(jié)果
![](/d/20211017/fc10a903efeb28cd716d9a263ac04030.gif)
3 說(shuō)明
當(dāng)使用 html/template 這個(gè)包時(shí),如果使用 template.HTML 函數(shù),也可以正常顯示,不使用 template.HTML 函數(shù),轉(zhuǎn)義顯示。
以上就是go web 預(yù)防跨站腳本的詳細(xì)內(nèi)容,更多關(guān)于go web 預(yù)防跨站的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- Python+Django+MySQL實(shí)現(xiàn)基于Web版的增刪改查的示例代碼
- 詳解Django3中直接添加Websockets方式
- python+Django+pycharm+mysql 搭建首個(gè)web項(xiàng)目詳解
- 使用Django搭建web服務(wù)器的例子(最最正確的方式)
- Django CSRF跨站請(qǐng)求偽造防護(hù)過程解析
- Django中如何防范CSRF跨站點(diǎn)請(qǐng)求偽造攻擊的實(shí)現(xiàn)