html/templates – 用<br>替换换行符

huangapple go评论102阅读模式
英文:

html/templates - Replacing newlines with <br>

问题

我正在加载一个包含换行符的文本文件,并将其传递给html/templates

在加载的字符串中,将\n替换为&lt;br&gt;,模板会将它们转义为html的&amp;lt;br&amp;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 &lt;br&gt; in the loaded string, they are escaped by the template to html &amp;lt;br&amp;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>&lt;script&gt;dangerous&lt;/script&gt;<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 (
	&quot;html/template&quot;
	&quot;os&quot;
	&quot;strings&quot;
)

const page = `&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;p&gt;{{.}}&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;`

const text = `first line
&lt;script&gt;dangerous&lt;/script&gt;
last line`

func main() {
	t := template.Must(template.New(&quot;page&quot;).Parse(page))
	safe := template.HTMLEscapeString(text)
	safe = strings.Replace(safe, &quot;\n&quot;, &quot;&lt;br&gt;&quot;, -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

&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;p&gt;first line&lt;br&gt;&amp;lt;script&amp;gt;dangerous&amp;lt;/script&amp;gt;&lt;br&gt;last line&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;

And text rendered in the browser is

first line
&lt;script&gt;dangerous&lt;/script&gt;
last line

答案2

得分: 4

不确定你在哪里将\n替换为&lt;br&gt;,但如果是在Go中,你可以将字符串转换为template.HTML,这样它就不会被转义。

参考:http://golang.org/pkg/html/template/#HTML

如果是在模板中,应该有一个可用的管道,{{. | html}}

英文:

Not sure where you're substituting \n for &lt;br&gt; 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>"))
}

Try it out!

英文:

You can do it like this:

package main

import (
	&quot;html/template&quot;
	&quot;os&quot;
)

const page = `&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;p&gt;{{.}}&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;`

func main() {
	t := template.Must(template.New(&quot;page&quot;).Parse(page))
	t.Execute(os.Stdout, template.HTML(&quot;&lt;br&gt;&quot;))
}

Try it out!

答案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>&lt;script&gt;dangerous&lt;/script&gt;<br>last line</p>
  </body>
</html>

Go Playground

英文:

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), &quot;\n&quot;, &quot;&lt;br&gt;&quot;, -1))
}

Add it with func (*Template) Funcs

Example

package main

import (
	&quot;html/template&quot;
	&quot;os&quot;
	&quot;strings&quot;
)

const page = `&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;body&gt;
    &lt;p&gt;{{. | replaceNewline}}&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;`

const text = `first line
&lt;script&gt;dangerous&lt;/script&gt;
last line`

func main() {
	t := template.Must(template.New(&quot;page&quot;).Funcs(template.FuncMap{
		&quot;replaceNewline&quot;: func(s string) template.HTML {
			return template.HTML(strings.Replace(template.HTMLEscapeString(s), &quot;\n&quot;, &quot;&lt;br&gt;&quot;, -1))
		},
	}).Parse(page))
	t.Execute(os.Stdout, text)
}

Output

&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;body&gt;
    &lt;p&gt;first line&lt;br&gt;&amp;lt;script&amp;gt;dangerous&amp;lt;/script&amp;gt;&lt;br&gt;last line&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;

Go Playground

答案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:    &lt;script&gt;alert(&quot;Owned!&quot;);&lt;/script&gt;

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 &quot;bytes&quot;
import &quot;fmt&quot;
import &quot;html/template&quot;
import &quot;strings&quot;

var input = `
  {{ define &quot;LAYOUT&quot; }}
    &lt;html&gt;
      &lt;body&gt;
        {{ template &quot;CONTENT&quot; . }}
      &lt;/body&gt;
    &lt;/html&gt;
  {{ end }}

  {{ define &quot;CONTENT&quot; }}
    Unsafe content: {{ .Unsafe }}
    Newlines converted to &lt;br/&gt; follow:
    {{ .Normal }}
  {{ end }}

  {{ template &quot;LAYOUT&quot; . }}
`

var other = `
  Hello
  World
  Again
`

var other2 = `
  &lt;script&gt;alert(&quot;Owned!&quot;);&lt;/script&gt;
`

func main() {

	var t, err = template.New(&quot;sample&quot;).Parse(input)
	if err != nil {
		panic(err)
	}

	var fixed = strings.Replace(other, &quot;\n&quot;, &quot;\n&lt;br/&gt;&quot;, -1)
	var model = map[string]interface{}{
		&quot;Normal&quot;: template.HTML(fixed),
		&quot;Unsafe&quot;: other2,
	}

	var out bytes.Buffer
	t.Execute(&amp;out, model) # &lt;--- !! Notice the model is NOT an HTML type.

	var raw = out.String()
	fmt.Printf(&quot;%s&quot;, raw)
}

Yields:

> <html>
> <body>
>
> Unsafe content: &lt;script&gt;alert(&#34;Owned!&#34;);&lt;/script&gt;
>
> Newlines converted to <br/> follow:
> <br/> Hello
> <br/> World
> <br/> Again
> <br/>
>
> </body>
> </html>

huangapple
  • 本文由 发表于 2012年12月8日 23:45:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/13779027.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定