英文:
html/templates - Replacing newlines with <br>
问题
我正在加载一个包含换行符的文本文件,并将其传递给html/templates
。
在加载的字符串中,将\n
替换为<br>
,模板会将它们转义为html的&lt;br&gt;
,并在浏览器中显示,而不是引起换行。
如何在不切换到没有XSS保护的text/templates
的情况下更改此行为?
英文:
I'm loading a text file that has newlines in it, and pass it to html/templates
.
Substituting the \n
with <br>
in the loaded string, they are escaped by the template to html &lt;br&gt;
and displayed in the browser, instead of causing a line return.
How can I change this behavior without switching to text/templates
(which doesn't have XSS protection)?
答案1
得分: 12
看起来你可以先在文本上运行template.HTMLEscape()来进行清理,然后进行\n到<br>的替换,然后将其作为预转义和可信任的模板数据使用。
更新:在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封装了一个已知安全的HTML文档片段。
}
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
英文:
It seems you could run template.HTMLEscape() on your text first to sanitize it, then do the \n to <br> substitution that you trust, then use that as pre-escaped and trusted template data.
Update: Expanding on Kocka's example, this is what I had in mind:
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
Output is
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>first line<br>&lt;script&gt;dangerous&lt;/script&gt;<br>last line</p>
</body>
</html>
And text rendered in the browser is
first line
<script>dangerous</script>
last line
答案2
得分: 4
不确定你在哪里将\n
替换为<br>
,但如果是在Go中,你可以将字符串转换为template.HTML
,这样它就不会被转义。
参考:http://golang.org/pkg/html/template/#HTML
如果是在模板中,应该有一个可用的管道,{{. | html}}
。
英文:
Not sure where you're substituting \n
for <br>
but if it's in go, you can cast the string as template.HTML
so it's not escaped.
See: http://golang.org/pkg/html/template/#HTML
If it's in a template, there should be a pipeline available, {{. | html}}
答案3
得分: 2
你可以像这样做:
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>"))
}
英文:
You can do it like this:
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>"))
}
答案4
得分: 2
接受的答案可以很容易地转换为自定义模板函数:
func replaceNewline(s string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>", -1))
}
使用func (*Template) Funcs
添加它。
示例
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>
英文:
The accepted answer can easily be turned into a custom template function:
func replaceNewline(s string) template.HTML {
return template.HTML(strings.Replace(template.HTMLEscapeString(s), "\n", "<br>", -1))
}
Add it with func (*Template) Funcs
Example
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)
}
Output
<!DOCTYPE html>
<html>
<body>
<p>first line<br>&lt;script&gt;dangerous&lt;/script&gt;<br>last line</p>
</body>
</html>
答案5
得分: 1
不需要将整个模板作为不安全模板传递(这是不好的做法)。
你应该将一个map传递给你的模板,并且只显式地将你想要使用的元素标记为'unsafe',例如:
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) # <--- !! 注意model不是HTML类型。
var raw = out.String()
fmt.Printf("%s", raw)
}
输出:
<html>
<body>
Unsafe content: <script>alert("Owned!");</script>
Newlines converted to <br/> follow:
<br/> Hello
<br/> World
<br/> Again
<br/>
</body>
</html>
英文:
It is unnecessary to pass your entire template as an unsafe template (and this is bad practice).
You should pass a map to your template, and only explicitly 'unsafe' the elements you want to use as such, eg.
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)
}
Yields:
> <html>
> <body>
>
> Unsafe content: <script>alert("Owned!");</script>
>
> Newlines converted to <br/> follow:
> <br/> Hello
> <br/> World
> <br/> Again
> <br/>
>
> </body>
> </html>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论