我正在加载一个包含换行符的文本文件,并将其传递给html/templates
.
在加载的字符串中替换\n
with <br>
,它们被模板转义为 html<br>
并显示在浏览器中,而不是导致换行。
如何在不切换到text/templates
(没有 XSS 保护)的情况下更改此行为?
看来您可以先在文本上运行 template.HTMLEscape() 以对其进行清理,然后执行 \n
替换您信任的替换,然后将其用作预转义和受信任的模板数据。
更新:扩展 Kocka 的示例,这就是我的想法:
package main
import (
"html/template"
"os"
"strings"
)
const page = `<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>{{.}}</p>
</body>
</html>`
const text = `first line
<script>dangerous</script>
last line`
func main() {
t := template.Must(template.New("page").Parse(page))
safe := template.HTMLEscapeString(text)
safe = strings.Replace(safe, "\n", "<br>", -1)
t.Execute(os.Stdout, template.HTML(safe)) // template.HTML encapsulates a known safe HTML document fragment.
}
http://play.golang.org/p/JiH0uD5Zh2
输出是
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>first line<br><script>dangerous</script><br>last line</p>
</body>
</html>
在浏览器中呈现的文本是
first line
<script>dangerous</script>
last line
不确定您要替换\n
的位置,<br>
但如果它正在运行,您可以转换字符串,template.HTML
这样它就不会被转义。
见: http: //golang.org/pkg/html/template/#HTML
如果它在模板中,应该有一个可用的管道,{{. | html}}
你可以这样做:
package main
import (
"html/template"
"os"
)
const page = `<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>{{.}}</p>
</body>
</html>`
func main() {
t := template.Must(template.New("page").Parse(page))
t.Execute(os.Stdout, template.HTML("<br>"))
}
接受的答案可以很容易地转换为自定义模板函数:
func replaceNewline(s string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>", -1))
}
例子
package main
import (
"html/template"
"os"
"strings"
)
const page = `<!DOCTYPE html>
<html>
<body>
<p>{{. | replaceNewline}}</p>
</body>
</html>`
const text = `first line
<script>dangerous</script>
last line`
func main() {
t := template.Must(template.New("page").Funcs(template.FuncMap{
"replaceNewline": func(s string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>", -1))
},
}).Parse(page))
t.Execute(os.Stdout, text)
}
输出
<!DOCTYPE html>
<html>
<body>
<p>first line<br><script>dangerous</script><br>last line</p>
</body>
</html>
没有必要将整个模板作为不安全的模板传递(这是不好的做法)。
您应该将地图传递给您的模板,并且只明确地“不安全”您想要使用的元素,例如。
package main
import "bytes"
import "fmt"
import "html/template"
import "strings"
var input = `
{{ define "LAYOUT" }}
<html>
<body>
{{ template "CONTENT" . }}
</body>
</html>
{{ end }}
{{ define "CONTENT" }}
Unsafe content: {{ .Unsafe }}
Newlines converted to <br/> follow:
{{ .Normal }}
{{ end }}
{{ template "LAYOUT" . }}
`
var other = `
Hello
World
Again
`
var other2 = `
<script>alert("Owned!");</script>
`
func main() {
var t, err = template.New("sample").Parse(input)
if err != nil {
panic(err)
}
var fixed = strings.Replace(other, "\n", "\n<br/>", -1)
var model = map[string]interface{}{
"Normal": template.HTML(fixed),
"Unsafe": other2,
}
var out bytes.Buffer
t.Execute(&out, model) # <--- !! Notice the model is NOT an HTML type.
var raw = out.String()
fmt.Printf("%s", raw)
}
产量:
Unsafe content: <script>alert("Owned!");</script> Newlines converted to <br/> follow: <br/> Hello <br/> World <br/> Again <br/> </body> </html>