mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-29 22:29:56 +02:00
@@ -12,14 +12,14 @@ 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
|
||||
# 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)
|
||||
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.
|
||||
@@ -34,38 +34,37 @@ provided below.
|
||||
|
||||
Example
|
||||
|
||||
import template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
|
||||
...
|
||||
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
|
||||
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
|
||||
import template "github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate"
|
||||
...
|
||||
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>!
|
||||
Hello, <script>alert('you have been pwned')</script>!
|
||||
|
||||
but the contextual autoescaping in html/template
|
||||
|
||||
import template "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"
|
||||
...
|
||||
t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
|
||||
err = t.ExecuteTemplate(out, "T", "<script>alert('you have been pwned')</script>")
|
||||
import template "github.com/gohugoio/hugo/tpl/internal/go_templates/htmltemplate"
|
||||
...
|
||||
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, <script>alert('you have been pwned')</script>!
|
||||
Hello, <script>alert('you have been pwned')</script>!
|
||||
|
||||
|
||||
Contexts
|
||||
# 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>
|
||||
<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>
|
||||
<a href="/search?q={{. | urlescaper | attrescaper}}">{{. | htmlescaper}}</a>
|
||||
|
||||
where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping
|
||||
functions.
|
||||
@@ -73,117 +72,113 @@ 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.
|
||||
|
||||
Namespaced and data- attributes
|
||||
# Namespaced and data- attributes
|
||||
|
||||
Attributes with a namespace are treated as if they had no namespace.
|
||||
Given the excerpt
|
||||
|
||||
<a my:href="{{.}}"></a>
|
||||
<a my:href="{{.}}"></a>
|
||||
|
||||
At parse time the attribute will be treated as if it were just "href".
|
||||
So at parse time the template becomes:
|
||||
|
||||
<a my:href="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a my:href="{{. | urlescaper | attrescaper}}"></a>
|
||||
|
||||
Similarly to attributes with namespaces, attributes with a "data-" prefix are
|
||||
treated as if they had no "data-" prefix. So given
|
||||
|
||||
<a data-href="{{.}}"></a>
|
||||
<a data-href="{{.}}"></a>
|
||||
|
||||
At parse time this becomes
|
||||
|
||||
<a data-href="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a data-href="{{. | urlescaper | attrescaper}}"></a>
|
||||
|
||||
If an attribute has both a namespace and a "data-" prefix, only the namespace
|
||||
will be removed when determining the context. For example
|
||||
|
||||
<a my:data-href="{{.}}"></a>
|
||||
<a my:data-href="{{.}}"></a>
|
||||
|
||||
This is handled as if "my:data-href" was just "data-href" and not "href" as
|
||||
it would be if the "data-" prefix were to be ignored too. Thus at parse
|
||||
time this becomes just
|
||||
|
||||
<a my:data-href="{{. | attrescaper}}"></a>
|
||||
<a my:data-href="{{. | attrescaper}}"></a>
|
||||
|
||||
As a special case, attributes with the namespace "xmlns" are always treated
|
||||
as containing URLs. Given the excerpts
|
||||
|
||||
<a xmlns:title="{{.}}"></a>
|
||||
<a xmlns:href="{{.}}"></a>
|
||||
<a xmlns:onclick="{{.}}"></a>
|
||||
<a xmlns:title="{{.}}"></a>
|
||||
<a xmlns:href="{{.}}"></a>
|
||||
<a xmlns:onclick="{{.}}"></a>
|
||||
|
||||
At parse time they become:
|
||||
|
||||
<a xmlns:title="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a xmlns:href="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a xmlns:onclick="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a xmlns:title="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a xmlns:href="{{. | urlescaper | attrescaper}}"></a>
|
||||
<a xmlns:onclick="{{. | urlescaper | attrescaper}}"></a>
|
||||
|
||||
Errors
|
||||
# Errors
|
||||
|
||||
See the documentation of ErrorCode for details.
|
||||
|
||||
|
||||
A fuller picture
|
||||
# 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
|
||||
# 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 <i>you</i>?
|
||||
<a title='{{.}}'> O'Reilly: How are you?
|
||||
<a href="/{{.}}"> O'Reilly: How are %3ci%3eyou%3c/i%3e?
|
||||
<a href="?q={{.}}"> O'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
|
||||
Context {{.}} After
|
||||
{{.}} O'Reilly: How are <i>you</i>?
|
||||
<a title='{{.}}'> O'Reilly: How are you?
|
||||
<a href="/{{.}}"> O'Reilly: How are %3ci%3eyou%3c/i%3e?
|
||||
<a href="?q={{.}}"> O'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
|
||||
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
|
||||
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" }
|
||||
struct{A,B string}{ "foo", "bar" }
|
||||
|
||||
in the escaped template
|
||||
|
||||
<script>var pair = {{.}};</script>
|
||||
<script>var pair = {{.}};</script>
|
||||
|
||||
then the template output is
|
||||
|
||||
<script>var pair = {"A": "foo", "B": "bar"};</script>
|
||||
<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
|
||||
# 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
|
||||
@@ -197,24 +192,23 @@ exempted from escaping.
|
||||
|
||||
The template
|
||||
|
||||
Hello, {{.}}!
|
||||
Hello, {{.}}!
|
||||
|
||||
can be invoked with
|
||||
|
||||
tmpl.Execute(out, template.HTML(`<b>World</b>`))
|
||||
tmpl.Execute(out, template.HTML(`<b>World</b>`))
|
||||
|
||||
to produce
|
||||
|
||||
Hello, <b>World</b>!
|
||||
Hello, <b>World</b>!
|
||||
|
||||
instead of the
|
||||
|
||||
Hello, <b>World<b>!
|
||||
Hello, <b>World<b>!
|
||||
|
||||
that would have been produced if {{.}} was a regular string.
|
||||
|
||||
|
||||
Security Model
|
||||
# Security Model
|
||||
|
||||
https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
|
||||
|
||||
|
Reference in New Issue
Block a user