html/template

Package template (html/template) implements data-driven templates for generating HTML output safe against code injection. It provides the same interface as package text/template and should be used instead of text/template whenever the output is HTML.

The documentation here focuses on the security features of the package. For information about how to program the templates themselves, see the documentation for text/template.

Introduction

This package wraps package text/template so you can share its template API to parse and execute HTML templates safely.

tmpl, err := template.New("name").Parse(...)
// Error checking elided
err = tmpl.Execute(out, data)

If successful, tmpl will now be injection-safe. Otherwise, err is an error defined in the docs for ErrorCode.

HTML templates treat data values as plain text which should be encoded so they can be safely embedded in an HTML document. The escaping is contextual, so actions can appear within JavaScript, CSS, and URI contexts.

The security model used by this package assumes that template authors are trusted, while Execute's data parameter is not. More details are provided below.

Example

import "text/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
produces

Hello, <script>alert('you have been pwned')</script>!
but the contextual autoescaping in html/template

import "html/template"
...
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")

produces safe, escaped HTML output

Hello, &lt;script&gt;alert(&#39;you have been pwned&#39;)&lt;/script&gt;!

Contexts

This package understands HTML, CSS, JavaScript, and URIs. It adds sanitizing functions to each simple action pipeline, so given the excerpt

<a href="/search?q={{.}}">{{.}}</a>

At parse time each {{.}} is overwritten to add escaping functions as necessary. In this case it becomes

<a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>

where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping functions.

For these internal escaping functions, if an action pipeline evaluates to a nil interface value, it is treated as though it were an empty string.

Errors

See the documentation of ErrorCode for details.

A fuller picture The rest of this package comment may be skipped on first reading; it includes details necessary to understand escaping contexts and error messages. Most users will not need to understand these details.

Contexts Assuming {{.}}is O'Reilly: How are <i>you</i>?, the table below shows how {{.}}appears when used in the context to the left.

Context                          {{.}} After
{{.}}                            O'Reilly: How are &lt;i&gt;you&lt;/i&gt;?
<a title='{{.}}'>                O&#39;Reilly: How are you?
<a href="/{{.}}">                O&#39;Reilly: How are %3ci%3eyou%3c/i%3e?
<a href="?q={{.}}">              O&#39;Reilly%3a%20How%20are%3ci%3e...%3f
<a onx='f("{{.}}")'>             O\x27Reilly: How are \x3ci\x3eyou...?
<a onx='f({{.}})'>               "O\x27Reilly: How are \x3ci\x3eyou...?"
<a onx='pattern = /{{.}}/;'>     O\x27Reilly: How are \x3ci\x3eyou...\x3f

If used in an unsafe context, then the value might be filtered out:

Context                          {{.}} After
<a href="{{.}}">                 #ZgotmplZ
since "O'Reilly:" is not an allowed protocol like "http:".

If {{.}} is the innocuous word, `left`, then it can appear more widely,

Context                              {{.}} After
{{.}}                                left
<a title='{{.}}'>                    left
<a href='{{.}}'>                     left
<a href='/{{.}}'>                    left
<a href='?dir={{.}}'>                left
<a style="border-{{.}}: 4px">        left
<a style="align: {{.}}">             left
<a style="background: '{{.}}'>       left
<a style="background: url('{{.}}')>  left
<style>p.{{.}} {color:red}</style>   left

Non-string values can be used in JavaScript contexts. If {{.}} is

struct{A,B string}{ "foo", "bar" } in the escaped template

<script>var pair = {{.}};</script>

then the template output is

<script>var pair = {"A": "foo", "B": "bar"};</script>

See package json to understand how non-string content is marshaled for embedding in JavaScript contexts.

Typed Strings By default, this package assumes that all pipelines produce a plain text string. It adds escaping pipeline stages necessary to correctly and safely embed that plain text string in the appropriate context.

When a data value is not plain text, you can make sure it is not over-escaped by marking it with its type.

Types HTML, JS, URL, and others from content.go can carry safe content that is exempted from escaping.

The template

Hello, {{.}}! can be invoked with

tmpl.Execute(out, template.HTML(`<b>World</b>`))

to produce

Hello, <b>World</b>!

instead of the

Hello, &lt;b&gt;World&lt;b&gt;!

that would have been produced if {{.}}was a regular string.

Security Model https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.

This package assumes that template authors are trusted, that Execute's data parameter is not, and seeks to preserve the properties below in the face of untrusted data:

Structure Preservation Property: "... when a template author writes an HTML tag in a safe templating language, the browser will interpret the corresponding portion of the output as a tag regardless of the values of untrusted data, and similarly for other structures such as attribute boundaries and JS and CSS string boundaries."

Code Effect Property: "... only code specified by the template author should run as a result of injecting the template output into a page and all code specified by the template author should run as a result of the same."

Least Surprise Property: "A developer (or code reviewer) familiar with HTML, CSS, and JavaScript, who knows that contextual autoescaping happens should be able to look at a {{.}}and correctly infer what sanitization happens."

API

    func HTMLEscape(w io.Writer, b []byte)
    func HTMLEscapeString(s string) string
    func HTMLEscaper(args ...interface{}) string
    func IsTrue(val interface{}) (truth, ok bool)
    func JSEscape(w io.Writer, b []byte)
    func JSEscapeString(s string) string
    func JSEscaper(args ...interface{}) string
    func URLQueryEscaper(args ...interface{}) string

type CSS
type Error

    func (e *Error) Error() string

type ErrorCode
type FuncMap
type HTML
type HTMLAttr
type JS
type JSStr
type Srcset
type Template

    func Must(t *Template, err error) *Template
    func New(name string) *Template
    func ParseFiles(filenames ...string) (*Template, error)
    func ParseGlob(pattern string) (*Template, error)
    func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error)
    func (t *Template) Clone() (*Template, error)
    func (t *Template) DefinedTemplates() string
    func (t *Template) Delims(left, right string) *Template
    func (t *Template) Execute(wr io.Writer, data interface{}) error
    func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error
    func (t *Template) Funcs(funcMap FuncMap) *Template
    func (t *Template) Lookup(name string) *Template
    func (t *Template) Name() string
    func (t *Template) New(name string) *Template
    func (t *Template) Option(opt ...string) *Template
    func (t *Template) Parse(text string) (*Template, error)
    func (t *Template) ParseFiles(filenames ...string) (*Template, error)
    func (t *Template) ParseGlob(pattern string) (*Template, error)
    func (t *Template) Templates() []*Template

type URL

common API

  • func (t *Template) ParseFiles(filenames ...string) (*Template, error)
    ParseFiles parses the named files and associates the resulting templates with t. If an error occurs, parsing stops and the returned template is nil; otherwise it is t. There must be at least one file.
    When parsing multiple files with the same name in different directories, the last one mentioned will be the one that results.
    ParseFiles returns an error if t or any associated template has already been executed.
  • func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error
    ExecuteTemplate applies the template associated with t that has the given name to the specified data object and writes the output to wr. If an error occurs executing the template or writing its output, execution stops, but partial results may already have been written to the output writer. A template may be executed safely in parallel, although if parallel executions share a Writer the output may be interleaved.
  • func (t *Template) Execute(wr io.Writer, data interface{}) error
    Execute applies a parsed template to the specified data object, writing the output to wr. If an error occurs executing the template or writing its output, execution stops, but partial results may already have been written to the output writer. A template may be executed safely in parallel, although if parallel executions share a Writer the output may be interleaved.

example

/*
* @Author: sottxiong
* @Date:   2019-08-23 12:33:42
* @Last Modified by:   sottxiong
* @Last Modified time: 2019-08-23 16:40:32
 */
package main

import (
    "fmt"
    "html/template"
    "net/http"
)

//Page
type NewAggPage struct {
    Title string
    News  string
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>hello world</h1>")
}

func newAggHandler(w http.ResponseWriter, r *http.Request) {
    p := NewAggPage{
        Title: "Amazing News Aggregator",
        News:  "some good news",
    }
    t, err := template.ParseFiles("test.html")
    if err != nil {
        panic(err)
    }
    t.Execute(w, p) //等价于 t.ExecuteTemplate(w, "test.html", p)

}
func main() {
    http.HandleFunc("/", indexHandler)
    http.HandleFunc("/agg/", newAggHandler)
    http.ListenAndServe(":8000", nil)
}

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
    <h3>{{ .Title }}</h3>
    <p>{{ .News }}</p>
</body>
</html>

注意,以下方式html tag是不会渲染的

<h3>{{ .Title }}</h3>
<p>{{ .News }}</p>

什么意思?你将得到如下,用chrome查看html source,外面包了个 pre标签

<h3>Amazing News Aggregator</h3>
<p>some good news</p>

results matching ""

    No results matching ""