10

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

在加载的字符串中替换\nwith <br>,它们被模板转义为 html&lt;br&gt;并显示在浏览器中,而不是导致换行。

如何在不切换到text/templates(没有 XSS 保护)的情况下更改此行为?

4

5 回答 5

12

看来您可以先在文本上运行 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>&lt;script&gt;dangerous&lt;/script&gt;<br>last line</p>
  </body>
</html>

在浏览器中呈现的文本是

first line
<script>dangerous</script>
last line
于 2012-12-08T21:59:35.850 回答
4

不确定您要替换\n的位置,<br>但如果它正在运行,您可以转换字符串,template.HTML这样它就不会被转义。

见: http: //golang.org/pkg/html/template/#HTML

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

于 2012-12-08T16:29:06.483 回答
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>"))
}

试试看!

于 2012-12-09T09:51:25.983 回答
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>

去游乐场

于 2020-12-09T10:31:29.350 回答
1

没有必要将整个模板作为不安全的模板传递(这是不好的做法)。

您应该将地图传递给您的模板,并且只明确地“不安全”您想要使用的元素,例如。

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

Newlines converted to <br/> follow:
 <br/>  Hello 
 <br/>  World 
 <br/>  Again 
 <br/>

  </body>
</html>
于 2013-02-28T05:53:25.940 回答