Go 視圖模板篇(四):上下文感知與 XSS 攻擊
Go 模板引擎一個(gè)有趣的地方是顯示內(nèi)容可以根據(jù)上下文變化,該功能的一個(gè)常見用處就是在適當(dāng)?shù)牡胤綄?duì)內(nèi)容進(jìn)行相應(yīng)的轉(zhuǎn)義。
上下文感知轉(zhuǎn)義
下面看個(gè)示例,編寫一段服務(wù)端處理器示例代碼:
package?main
import?(
????"html/template"
????"net/http"
)
func?contextExample(w?http.ResponseWriter,?r?*http.Request)??{
????t?:=?template.Must(template.ParseFiles("context.html"))
????content?:=?`I?asked:?"What's?up?"`
????t.Execute(w,?content)
}
func?main()??{
????http.HandleFunc("/context",?contextExample)
????http.ListenAndServe(":8080",?nil)
}
對(duì)應(yīng)的模板文件 context.html 代碼:
<html?lang="en">
<head>
????<meta?charset="UTF-8">
????<title>Context-aware?Demotitle>
head>
<body>
????<div>{{?.?}}div>
????<div><a?href="/{{?.?}}">Patha>div>
????<div><a?href="/?q={{?.?}}">Querya>div>
????<div><a?onclick="f('{{?.?}}')">Onclicka>div>
body>
html>
運(yùn)行服務(wù)端代碼啟動(dòng)服務(wù)器,在終端窗口通過 curl 發(fā)起模擬請(qǐng)求,可以看到傳入模板的內(nèi)容會(huì)在不同的地方進(jìn)行不同形式的轉(zhuǎn)義:

這就是 Go 視圖模板的上下文感知特性,它可以根據(jù)指令的位置輸出不同的內(nèi)容:

排除 XSS 攻擊
我們可以基于這個(gè)特性在 Go 視圖模板中防止 XSS 攻擊。
服務(wù)端示例代碼:
package?main
import?(
????"html/template"
????"net/http"
)
func?xssAttackExample(w?http.ResponseWriter,?r?*http.Request)??{
????t?:=?template.Must(template.ParseFiles("xss.html"))
????if?r.Method?==?"GET"?{
????????t.Execute(w,?nil)
????}?else?{
????????t.Execute(w,?r.FormValue("comment"))
????}
}
func?main()??{
????http.HandleFunc("/xss",?xssAttackExample)
????http.ListenAndServe(":8080",?nil)
}
模板文件 xss.html 代碼:
<html?lang="en">
<head>
????<meta?charset="UTF-8">
????<title>XSS?Attacktitle>
head>
<body>
????<form?action="/xss"?method="post">
????????Comment:?<input?name="comment"?type="text"?value="{{?.?}}"?size="32">
????????<hr/>
????????<button?id="submit">Submitbutton>
????form>
body>
html>
啟動(dòng)服務(wù)端代碼,在瀏覽器中訪問 http://localhost:8080/xss,在下面這個(gè)略顯簡(jiǎn)陋的表單輸入包含 JavaScript 代碼的內(nèi)容并提交:


可以看到視圖模板中顯示的是對(duì)應(yīng)的 HTML 實(shí)體代碼,而不是執(zhí)行這段 JavaScript 代碼,這里就應(yīng)用了上下文感知的功能自動(dòng)對(duì) JavaScript 代碼進(jìn)行轉(zhuǎn)義,我們可以在瀏覽器開發(fā)者工具通過源代碼看到轉(zhuǎn)義后的 JavaScript 代碼:

上下文感知支持 HTML、URL、JavaScript 以及 CSS 格式文本的轉(zhuǎn)義。
不轉(zhuǎn)義 HTML
有的時(shí)候,我們不希望對(duì) HTML 代碼進(jìn)行轉(zhuǎn)義,比如富文本就是這樣的場(chǎng)景。Go 對(duì)此提供了支持,只需要調(diào)用 template.HTML 方法對(duì)其進(jìn)行類型轉(zhuǎn)化即可:
func?xssAttackExample(w?http.ResponseWriter,?r?*http.Request)?{?
????t,?_?:=?template.ParseFiles("tmpl.html")?
????t.Execute(w,?template.HTML(r.FormValue("comment")))?
}
對(duì)應(yīng)的模板文件也要調(diào)整,因?yàn)檩斎肟蛑谐霈F(xiàn) JavaScript 代碼渲染的時(shí)候會(huì)自動(dòng)去除:
<form?action="/xss"?method="post">
????Comment:?<input?name="comment"?type="text"?value="{{?.?}}"?size="32">
????<hr/>
????<button?id="submit">Submitbutton>
form>
<div>Comment:?{{?.?}}div>
再次啟動(dòng)服務(wù)端代碼,這次在瀏覽器訪問 /xss 路由,就會(huì)執(zhí)行對(duì)應(yīng)的 JavaScript 代碼了:

(全文完)
推薦閱讀
站長(zhǎng) polarisxu
自己的原創(chuàng)文章
不限于 Go 技術(shù)
職場(chǎng)和創(chuàng)業(yè)經(jīng)驗(yàn)
Go語言中文網(wǎng)
每天為你
分享 Go 知識(shí)
Go愛好者值得關(guān)注
