text与html模板的区别

text与html模板的区别

html/template针对的是需要返回HTML内容的场景,在模板渲染过程中会对一些有风险的内容进行转义,以此来防范跨站脚本攻击。

image-20211111224009410

image-20211111225242590

一、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>

image-20211111225438672

二、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>

image-20211111225723034

这个时候传入一段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 }}

image-20211111231622732

image-20211111231611918

posted @ 2021-11-29 23:16  RandySun  阅读(291)  评论(0编辑  收藏  举报