text与html模板的区别
text与html模板的区别
html/template
针对的是需要返回HTML内容的场景,在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击。
一、text/template
package main
import (
"fmt"
"net/http"
"text/template" // 导入text模板
)
func xss(w http.ResponseWriter, r *http.Request) {
// 定义模板
// 解析模板
// 自定默认的标识符
t, err := template.ParseFiles("./xss.tmpl")
if err != nil{
fmt.Printf("parse tmpl falied err:%#v\n", err)
}
// 渲染模板
str := "<script>alert(123);</script>" // text会被解析为html标记语言
//str := "<a href='www.baidu.com'>百度</a>"
err = t.Execute(w, str)
if err != nil{
fmt.Printf("execute template failed err: %#v", err)
return
}
}
func main() {
http.HandleFunc("/customDefined", customDefined)
http.HandleFunc("/xss", xss)
err := http.ListenAndServe(":9999", nil)
if err != nil{
fmt.Printf("http server run faild err:%#V", err)
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello Template</title>
</head>
<body>
<p>用户的评论是:{{.}}</p>
</body>
</html>
二、html/tempalte
package main
import (
"fmt"
"html/template" // 导入html模板
"net/http"
)
func xss(w http.ResponseWriter, r *http.Request) {
// 定义模板
// 解析模板
// 自定默认的标识符
t, err := template.ParseFiles("./xss.tmpl")
if err != nil{
fmt.Printf("parse tmpl falied err:%#v\n", err)
}
// 渲染模板
str := "<script>alert(123);</script>" // 不会被解析html标记语言
//str := "<a href='www.baidu.com'>百度</a>"
err = t.Execute(w, str)
if err != nil{
fmt.Printf("execute template failed err: %#v", err)
return
}
}
func main() {
http.HandleFunc("/customDefined", customDefined)
http.HandleFunc("/xss", xss)
err := http.ListenAndServe(":9999", nil)
if err != nil{
fmt.Printf("http server run faild err:%#V", err)
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello Template</title>
</head>
<body>
<p>用户的评论是:{{.}}</p>
</body>
</html>
这个时候传入一段JS代码并使用html/template
去渲染该文件,会在页面上显示出转义后的JS内容。用户的评论是:<script>alert(123);</script>
这就是html/template
为我们做的事。
但是在某些场景下,我们如果相信用户输入的内容,不想转义的话,可以自行编写一个safe函数,手动返回一个template.HTML
类型的内容。示例如下:
package main
import (
"fmt"
"html/template"
"net/http"
)
func xssSafe(w http.ResponseWriter, r *http.Request) {
// 定义模板
// 解析模板
// 自定默认的标识符
t, err := template.New("xss.tmpl").Funcs(
template.FuncMap{
"safe": func(s string) template.HTML {
return template.HTML(s)
},
},
).ParseFiles("./xss.tmpl")
if err != nil {
fmt.Printf("parse tmpl falied err:%#v\n", err)
}
// 渲染模板
str1 := "<script>alert(123);</script>"
str2 := "<a href='https://www.cnblogs.com/randysun/'>博客</a>"
err = t.Execute(w, map[string]string{
"str1": str1,
"str2": str2,
})
if err != nil {
fmt.Printf("execute template failed err: %#v", err)
return
}
}
func main() {
http.HandleFunc("/xssSafe", xssSafe)
err := http.ListenAndServe(":9999", nil)
if err != nil {
fmt.Printf("http server run faild err:%#V", err)
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Hello Template</title>
</head>
<body>
<p>用户的评论是:{{.str1 | safe}}</p>
<p>博客:{{.str2 | safe}}</p>
</body>
</html>
这样我们只需要在模板文件不需要转义的内容后面使用我们定义好的safe函数就可以了。
{{ . | safe }}
在当下的阶段,必将由程序员来主导,甚至比以往更甚。