Involved Source Filescontext.godelim_string.go
Package template (safehtml/template) implements data-driven templates for
generating HTML output safe against code injection. It provides an interface
similar to that of package html/template, but produces HTML output that is more
secure. Therefore, it should be used instead of html/template to render 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.
Basic usage
This package provides an API almost identical to that of text/template and
html/template to parse and execute HTML templates safely.
tmpl := template.Must(template.New("name").Parse(`<div>Hello {{.}}</div>`))
err := tmpl.Execute(out, data)
If successful, out will contain code-injection-safe HTML. Otherwise, err's
string representation will describe the error that occurred.
Elements of data might be modified at run time before being included in out, or
rejected completely if such a conversion is not possible. Pass values of
appropriate types from package safehtml to ensure that they are included in the
template's HTML output in their expected form. More details are provided below
in "Contextual autosanitization" and "Sanitization contexts".
Security improvements
safehtml/template produces HTML more resistant to code injection than
html/template because it:
* Allows values of types only from package safehtml to bypass run-time
sanitization. These types represent values that are known---by construction
or by run-time sanitization---to be safe for use in various HTML contexts
without being processed by certain sanitization functions.
* Does not attempt to escape CSS or JavaScript. Instead of attempting to
parse and escape these complex languages, safehtml/template allows values
of only the appropriate types from package safehtml (e.g. safehtml.Style,
safehtml.Script) to be used in these contexts, since they are already
guaranteed to be safe.
* Emits an error if user data is interpolated in unsafe contexts, such as
within non-whitelisted elements or unquoted attribute values.
* Only loads templates from trusted sources. This ensures that the contents
of the template are always under programmer control. More details are
provided below in "Trusted template sources".
* Differentiates between URLs that load code and those that do not. URLs in
the former category must be supplied to the template as values of type
safehtml.TrustedResourceURL, whose type contract promises that the URL
identifies a trustworthy resource. URLs in the latter category can be
sanitized at run time.
Threat model
safehtml/template assumes that programmers are trustworthy. Therefore, data
fully under programmer control, such as string literals, are considered safe.
The types from package safehtml are designed around this same assumption, so
their type contracts are trusted by this package.
safehtml/template considers all other data values untrustworthy and
conservatively assumes that such values could result in a code-injection
vulnerability if included verbatim in HTML.
Trusted template sources
safehtml/template loads templates only from trusted sources. Therefore, template
text, file paths, and file patterns passed to Parse* functions and methods must
be entirely under programmer control.
This constraint is enforced by using unexported string types for the parameters
of Parse* functions and methods, such as trustedFilePattern for ParseGlob.
The only values that may be assigned to these types (and thus provided as
arguments) are untyped string constants such as string literals, which are
always under programmer control.
Contextual autosanitization
Code injection vulnerabilities, such as cross-site scripting (XSS), occur when
untrusted data values are embedded in a HTML document. For example,
import "text/template"
...
var t = template.Must(template.New("foo").Parse(`<a href="{{ .X }}">{{ .Y }}</a>`))
func renderHTML(x, y string) string {
var out bytes.Buffer
err := t.Execute(&out, struct{ X, Y string }{x, y})
// Error checking elided
return out.String()
}
If x and y originate from user-provided data, an attacker who controls these
strings could arrange for them to contain the following values:
x = "javascript:evil()"
y = "</a><script>alert('pwned')</script><a>"
which will cause renderHTML to return the following unsafe HTML:
<a href="javascript:evil()"></a><script>alert('pwned')</script><a></a>
To prevent such vulnerabilities, untrusted data must be sanitized before being
included in HTML. A sanitization function takes untrusted data and returns a
string that will not create a code-injection vulnerability in the destination
context. The function might return the input unchanged if it deems it safe,
escape special runes in the input's string representation to prevent them from
triggering undesired state changes in the HTML parser, or entirely replace the
input by an innocuous string (also known as "filtering"). If none of these
conversions are possible, the sanitization function aborts template processing.
safehtml/template contextually autosanitizes untrusted data by adding
appropriate sanitization functions to template actions to ensure that the
action output is safe to include in the HTML context in which the action
appears. For example, in
import "safehtml/template"
...
var t = template.Must(template.New("foo").Parse(`<a href="{{ .X }}">{{ .Y }}</a>`))
func renderHTML(x, y string) string {
var out bytes.Buffer
err := t.Execute(&out, struct{ X, Y string }{x, y})
// Error checking elided
return out.String()
}
the contextual autosanitizer rewrites the template to
<a href="{{ .X | _sanitizeTrustedResourceURLOrURL | _sanitizeHTML }}">{{ .Y | _sanitizeHTML }}</a>
so that the template produces the following safe, sanitized HTML output (split
across multiple lines for clarity):
<a href="about:invalid#zGoSafez">
</a><script>alert('pwned')</script><a>
</a>
Similar template systems such as html/template, Soy, and Angular, refer to this
functionality as "contextual autoescaping". safehtml/template uses the term
"autosanitization" instead of "autoescaping" since "sanitization" broadly
captures the operations of escaping and filtering.
Sanitization contexts
The types of sanitization functions inserted into an action depend on the
action's sanitization context, which is determined by its surrounding text.
The following table describes these sanitization contexts.
+--------------------+----------------------------------+------------------------------+-----------------------+
| Context | Examples | Safe types | Run-time sanitizer |
|--------------------+----------------------------------+------------------------------+-----------------------+
| HTMLContent | Hello {{.}} | safehtml.HTML | safehtml.HTMLEscaped |
| | <title>{{.}}</title> | | |
+--------------------------------------------------------------------------------------------------------------+
| HTMLValOnly | <iframe srcdoc="{{.}}"></iframe> | safehtml.HTML* | N/A |
+--------------------------------------------------------------------------------------------------------------+
| URL | <q cite="{{.}}">Cite</q> | safehtml.URL | safehtml.URLSanitized |
+--------------------------------------------------------------------------------------------------------------+
| URL or | <a href="{{.}}">Link</a> | safehtml.URL | safehtml.URLSanitized |
| TrustedResourceURL | | safehtml.TrustedResourceURL | |
+--------------------------------------------------------------------------------------------------------------+
| TrustedResourceURL | <script src="{{.}}"></script> | safehtml.TrustedResourceURL† | N/A |
+--------------------------------------------------------------------------------------------------------------+
| Script | <script>{{.}}</script> | safehtml.Script* | N/A |
+--------------------------------------------------------------------------------------------------------------+
| Style | <p style="{{.}}">Paragraph</p> | safehtml.Style* | N/A |
+--------------------------------------------------------------------------------------------------------------+
| Stylesheet | <style>{{.}}</style> | safehtml.StyleSheet* | N/A |
+--------------------------------------------------------------------------------------------------------------+
| Identifier | <h1 id="{{.}}">Hello</h1> | safehtml.Identifier* | N/A |
+--------------------------------------------------------------------------------------------------------------+
| Enumerated value | <a target="{{.}}">Link</a> | Whitelisted string values | N/A |
| | | ("_self" or "_blank" for | |
| | | the given example) | |
+--------------------------------------------------------------------------------------------------------------+
| None | <h1 class="{{.}}">Hello</h1> | N/A (any type allowed) | N/A (any type |
| | | | allowed) |
+--------------------+----------------------------------+------------------------------+-----------------------+
*: Values only of this type are allowed in this context. Other values will trigger a run-time error.
†: If the action is a prefix of the attribute value, values only of this type are allowed.
Otherwise, values of any type are allowed. See "Substitutions in URLs" for more details.
For each context, the function named in "Run-time sanitizer" is called to
sanitize the output of the action. However, if the action outputs a value of
any of the types listed in "Safe types", the run-time sanitizer is not called.
For example, in
<title>{{ .X }}</title>
if X is a string value, a HTML sanitizer that calls safehtml.HTMLEscaped will be
added to the action to sanitize X.
// _sanitizeHTML calls safehtml.HTMLEscaped.
<title>{{ .X | _sanitizeHTML }}</title>
However, if X is a safehtml.HTML value, _sanitizeHTML will not change its
value, since safehtml.HTML values are already safe to use in HTML contexts.
Therefore, the string contents of X will bypass context-specific
sanitization (in this case, HTML escaping) and appear unchanged in the
template's HTML output. Note that in attribute value contexts, HTML escaping
will always take place, whether or not context-specific sanitization is
performed. More details can be found at the end of this section.
In certain contexts, the autosanitizer allows values only of that context's
"Safe types". Any other values will trigger an error and abort template
processing. For example, the template
<style>{{ .X }}</style>
triggers a run-time error if X is not a safehtml.StyleSheet. Otherwise, the
string form of X will appear unchanged in the output. The only exception to
this behavior is in TrustedResourceURL sanitization contexts, where actions may
output data of any type if the action occurs after a safe attribute value prefix.
More details can be found below in "Substitutions in URLs".
Unconditional sanitization
In attribute value contexts, action outputs are always HTML-escaped after
context-specific sanitization to ensure that the attribute values cannot change
change the structure of the surrounding HTML tag. In URL or TrustedResourceURL
sanitization contexts, action outputs are additionally URL-normalized to reduce
the likelihood of downstream URL-parsing bugs. For example, the template
<a href="{{ .X }}">Link</a>
<p id="{{ .Y }}">Text</p>
is rewritten by the autosanitizer into
// _sanitizeHTML calls safehtml.HTMLEscaped.
<a href="{{ .X | _sanitizeTrustedResourceURLOrURL | _normalizeURL | _sanitizeHTML }}">Link</a>
<p id="{{ .Y | _sanitizeIdentifier | _sanitizeHTML }}">Text</p>
Even if X is a safehtml.URL or safehtml.TrustedResourceURL value, which
remains unchanged after _sanitizeTrustedResourceURLOrURL, X will still be
URL-normalized and HTML-escaped. Likewise, Y will still be HTML-escaped even if
its string form is left unchanged by _sanitizeIdentifier.
Substitutions in URLs
Values of any type may be substituted into attribute values in URL and
TrustedResourceURL sanitization contexts only if the action is preceded by a
safe URL prefix. For example, in
<q cite="http://www.foo.com/{{ .PathComponent }}">foo</q>
Since "http://www.foo.com/" is a safe URL prefix, PathComponent can safely be
interpolated into this URL sanitization context after URL normalization.
Similarly, in
<script src="https://www.bar.com/{{ .PathComponent }}"></script>
Since "https://www.bar.com/" is a safe TrustedResourceURL prefix, PathComponent
can safely be interpolated into this TrustedResourceURL sanitization context
after URL escaping. Substitutions after a safe TrustedResourceURL prefix are
escaped instead of normalized to prevent the injection of any new URL
components, including additional path components. URL escaping also takes place
in URL sanitization contexts where the substitutions occur in the query or
fragment part of the URL, such as in:
<a href="/foo?q={{ .Query }}&hl={{ .LangCode }}">Link</a>
A URL prefix is considered safe in a URL sanitization context if it does
not end in an incomplete HTML character reference (e.g. https) or incomplete
percent-encoding character triplet (e.g. /fo%6), does not contain whitespace or control
characters, and one of the following is true:
* The prefix has a safe scheme (i.e. http, https, mailto, or ftp).
* The prefix has the data scheme with base64 encoding and a whitelisted audio, image,
or video MIME type (e.g. data:img/jpeg;base64, data:video/mp4;base64).
* The prefix has no scheme at all, and cannot be interpreted as a scheme prefix (e.g. /path).
A URL prefix is considered safe in a TrustedResourceURL sanitization context if it does
not end in an incomplete HTML character reference (e.g. https) or incomplete
percent-encoding character triplet (e.g. /fo%6), does not contain white space or control
characters, and one of the following is true:
* The prefix has the https scheme and contains a domain name (e.g. https://www.foo.com).
* The prefix is scheme-relative and contains a domain name (e.g. //www.foo.com/).
* The prefix is path-absolute and contains a path (e.g. /path).
* The prefix is "about:blank".
error.goescape.goinit.gosanitize.gosanitizers.gostate_string.gotemplate.gotransition.gotrustedsource.gotrustedtemplate.gourl.goversionspecific_go111.go
{{end}}
`
check := func(err error) {
if err != nil {
log.Fatal(err)
}
}
t, err := template.New("webpage").Parse(tpl)
check(err)
data := struct {
Title string
Items []string
}{
Title: "My page",
Items: []string{
"My photos",
"My blog",
},
}
err = t.Execute(os.Stdout, data)
check(err)
noItems := struct {
Title string
Items []string
}{
Title: "My another page",
Items: []string{},
}
err = t.Execute(os.Stdout, noItems)
check(err)
}
package main
import (
"github.com/google/safehtml/template"
"log"
"os"
"strings"
)
func main() {
const (
master = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
overlay = `{{define "list"}} {{join . ", "}}{{end}} `
)
var (
funcs = template.FuncMap{"join": strings.Join}
guardians = []string{"Gamora", "Groot", "Nebula", "Rocket", "Star-Lord"}
)
masterTmpl, err := template.New("master").Funcs(funcs).Parse(master)
if err != nil {
log.Fatal(err)
}
overlayTmpl, err := template.Must(masterTmpl.Clone()).Parse(overlay)
if err != nil {
log.Fatal(err)
}
if err := masterTmpl.Execute(os.Stdout, guardians); err != nil {
log.Fatal(err)
}
if err := overlayTmpl.Execute(os.Stdout, guardians); err != nil {
log.Fatal(err)
}
}
package main
import (
"github.com/google/safehtml/template"
"log"
"os"
)
func main() {
t := template.Must(template.New("foo").Parse(`{{ .Y }}`))
renderHTML := func(x, y string) {
if err := t.Execute(os.Stdout, struct{ X, Y string }{x, y}); err != nil {
log.Fatal(err)
}
}
renderHTML("javascript:evil()", "")
}
Package-Level Type Names (total 15, in which 6 are exported)
/* sort exporteds by: | */
Error describes a problem encountered during template Escaping.
Description is a human-readable description of the problem.
ErrorCode describes the kind of error.
Line is the line number of the error in the template source or 0.
Name is the name of the template in which the error was encountered.
Node is the node that caused the problem, if known.
If not nil, it overrides Name and Line.
(*T) Error() string
*T : error
func eatAttrName(s []byte, i int) (int, *Error)
func errorf(k ErrorCode, node parse.Node, line int, f string, args ...interface{}) *Error
FuncMap is the type of the map defining the mapping from names to
functions. Each function must have either a single return value, or two
return values of which the second has type error. In that case, if the
second (error) argument evaluates to non-nil during execution, execution
terminates and Execute returns that error. FuncMap has the same base type
as FuncMap in "text/template", copied here so clients need not import
"text/template".
func (*Template).Funcs(funcMap FuncMap) *Template
var golang.org/x/pkgsite/internal/frontend.templateFuncs
Template is a specialized Template from "text/template" that produces a safe
HTML document fragment.
The underlying template's parse tree, updated to be HTML-safe.
Sticky error if escaping fails, or errEscapeOK if succeeded.
// common to all associated templates
cspCompatible indicates whether inline event handlers and
javascript: URIs are disallowed in templates in this namespace.
nameSpace.escescapernameSpace.escapedboolnameSpace.musync.MutexnameSpace.setmap[string]*Template
We could embed the text/template field, but it's safer not to because
we need to keep our version of the name space and the underlying
template's in sync.
CSPCompatible causes this template to check template text for
Content Security Policy (CSP) compatibility. The template will return errors
at execution time if inline event handler attribute names or javascript:
URIs are found in template text.
For example, the following templates will cause errors:
<span onclick="doThings();">A thing.</span> // inline event handler "onclick"
<a href="javascript:linkClicked()">foo</a> // javascript: URI present
Clone returns a duplicate of the template, including all associated
templates. The actual representation is not copied, but the name space of
associated templates is, so further calls to Parse in the copy will add
templates to the copy but not to the original. Clone can be used to prepare
common templates and use them with variant definitions for other templates
by adding the variants after the clone is made.
It returns an error if t has already been executed.
DefinedTemplates returns a string listing the defined templates,
prefixed by the string "; defined templates are: ". If there are none,
it returns the empty string. Used to generate an error message.
Delims sets the action delimiters to the specified strings, to be used in
subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template
definitions will inherit the settings. An empty delimiter stands for the
corresponding default: {{ or }}.
The return value is the template, so calls can be chained.
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.
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.
ExecuteTemplateToHTML applies the template associated with t that has
the given name to the specified data object and returns the output as
a safehtml.HTML value.
A template may be executed safely in parallel.
ExecuteToHTML applies a parsed template to the specified data object,
returning the output as a safehtml.HTML value.
A template may be executed safely in parallel.
Funcs adds the elements of the argument map to the template's function map.
It must be called before the template is parsed.
It panics if a value in the map is not a function with appropriate return
type. However, it is legal to overwrite elements of the map. The return
value is the template, so calls can be chained.
Lookup returns the template with the given name that is associated with t,
or nil if there is no such template.
Name returns the name of the template.
New allocates a new HTML template associated with the given one
and with the same delimiters. The association, which is transitive,
allows one template to invoke another with a {{template}} action.
If a template with the given name already exists, the new HTML template
will replace it. The existing template will be reset and disassociated with
t.
Option sets options for the template. Options are described by
strings, either a simple string or "key=value". There can be at
most one equals sign in an option string. If the option string
is unrecognized or otherwise invalid, Option panics.
Known options:
missingkey: Control the behavior during execution if a map is
indexed with a key that is not present in the map.
"missingkey=default" or "missingkey=invalid"
The default behavior: Do nothing and continue execution.
If printed, the result of the index operation is the string
"<no value>".
"missingkey=zero"
The operation returns the zero value for the map type's element.
"missingkey=error"
Execution stops immediately with an error.
Parse parses text as a template body for t.
Named template definitions ({{define ...}} or {{block ...}} statements) in text
define additional templates associated with t and are removed from the
definition of t itself.
Templates can be redefined in successive calls to Parse,
before the first use of Execute on t or any associated template.
A template definition with a body containing only white space and comments
is considered empty and will not replace an existing template's body.
This allows using Parse to add new named template definitions without
overwriting the main template body.
To guarantee that the template body is never controlled by an attacker, text
must be an untyped string constant, which is always under programmer control.
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.
To guarantee that filepaths, and thus template bodies, are never controlled by
an attacker, filenames must be untyped string constants, which are always under
programmer control.
ParseFilesFromTrustedSources 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.
ParseFilesFromTrustedSources returns an error if t or any associated template has already been executed.
To guarantee that filepaths, and thus template bodies, are never controlled by
an attacker, filenames must be trusted sources, which are always under programmer
or application control.
ParseFromTrustedTemplate parses tmpl as a template body for t.
Named template definitions ({{define ...}} or {{block ...}} statements) in text
define additional templates associated with t and are removed from the
definition of t itself.
Templates can be redefined in successive calls to ParseFromTrustedTemplate,
before the first use of Execute on t or any associated template.
A template definition with a body containing only white space and comments
is considered empty and will not replace an existing template's body.
This allows using ParseFromTrustedTemplate to add new named template definitions without
overwriting the main template body.
To guarantee that the template body is never controlled by an attacker, tmpl
is a TrustedTemplate, which is always under programmer control.
ParseGlob parses the template definitions in the files identified by the
pattern and associates the resulting templates with t. The pattern is
processed by filepath.Glob and must match at least one file. ParseGlob is
equivalent to calling t.ParseFiles with the list of files matched by the
pattern.
When parsing multiple files with the same name in different directories,
the last one mentioned will be the one that results.
ParseGlob returns an error if t or any associated template has already been executed.
To guarantee that the pattern, and thus the template bodies, is never controlled by
an attacker, pattern must be an untyped string constant, which is always under
programmer control.
ParseGlobFromTrustedSource parses the template definitions in the files identified by the
pattern and associates the resulting templates with t. The pattern is
processed by filepath.Glob and must match at least one file. ParseGlob is
equivalent to calling t.ParseFiles with the list of files matched by the
pattern.
When parsing multiple files with the same name in different directories,
the last one mentioned will be the one that results.
ParseGlobFromTrustedSource returns an error if t or any associated template has already been executed.
To guarantee that the pattern, and thus the template bodies, is never controlled by
an attacker, pattern must be a trusted source, which is always under programmer or
application control.
Templates returns a slice of the templates associated with t, including t
itself.
checkCanParse checks whether it is OK to parse templates.
If not, it returns an error.
escape escapes all associated templates.
lookupAndEscapeTemplate guarantees that the template with the given name
is escaped, or returns an error if it cannot be. It returns the named
template.
new is the implementation of New, without the lock.
func Must(t *Template, err error) *Template
func New(name string) *Template
func ParseFiles(filenames ...stringConstant) (*Template, error)
func ParseFilesFromTrustedSources(filenames ...TrustedSource) (*Template, error)
func ParseGlob(pattern stringConstant) (*Template, error)
func ParseGlobFromTrustedSource(pattern TrustedSource) (*Template, error)
func (*Template).Clone() (*Template, error)
func (*Template).CSPCompatible() *Template
func (*Template).Delims(left, right string) *Template
func (*Template).Funcs(funcMap FuncMap) *Template
func (*Template).Lookup(name string) *Template
func (*Template).New(name string) *Template
func (*Template).Option(opt ...string) *Template
func (*Template).Parse(text stringConstant) (*Template, error)
func (*Template).ParseFiles(filenames ...stringConstant) (*Template, error)
func (*Template).ParseFilesFromTrustedSources(filenames ...TrustedSource) (*Template, error)
func (*Template).ParseFromTrustedTemplate(tmpl TrustedTemplate) (*Template, error)
func (*Template).ParseGlob(pattern stringConstant) (*Template, error)
func (*Template).ParseGlobFromTrustedSource(pattern TrustedSource) (*Template, error)
func (*Template).Templates() []*Template
func parseFiles(t *Template, filenames ...string) (*Template, error)
func parseGlob(t *Template, pattern string) (*Template, error)
func (*Template).lookupAndEscapeTemplate(name string) (tmpl *Template, err error)
func (*Template).new(name string) *Template
func golang.org/x/pkgsite/internal/frontend.parsePageTemplates(base TrustedSource) (map[string]*Template, error)
func golang.org/x/pkgsite/internal/frontend.(*Server).findTemplate(templateName string) (*Template, error)
func golang.org/x/pkgsite/internal/worker.parseTemplate(staticPath, filename TrustedSource) (*Template, error)
func Must(t *Template, err error) *Template
func golang.org/x/pkgsite/internal/godoc/dochtml/internal/render.ExecuteToHTML(tmpl *Template, data interface{}) safehtml.HTML
func escapeTemplate(tmpl *Template, node parse.Node, name string) error
func parseFiles(t *Template, filenames ...string) (*Template, error)
func parseGlob(t *Template, pattern string) (*Template, error)
func golang.org/x/pkgsite/internal/frontend.executeTemplate(ctx context.Context, templateName string, tmpl *Template, data interface{}) ([]byte, error)
func golang.org/x/pkgsite/internal/godoc/dochtml.executeToHTMLWithLimit(tmpl *Template, data interface{}, limit int64) (safehtml.HTML, error)
func golang.org/x/pkgsite/internal/godoc/dochtml/internal/render.codeHTML(src string, codeTmpl *Template) safehtml.HTML
func golang.org/x/pkgsite/internal/worker.renderPage(ctx context.Context, w http.ResponseWriter, page interface{}, tmpl *Template) (err error)
var golang.org/x/pkgsite/internal/godoc/dochtml/internal/render.LinkTemplate *Template
var golang.org/x/pkgsite/internal/godoc/dochtml.bodyTemplate *template.Template
var golang.org/x/pkgsite/internal/godoc/dochtml.outlineTemplate *template.Template
var golang.org/x/pkgsite/internal/godoc/dochtml.sidenavTemplate *template.Template
var golang.org/x/pkgsite/internal/godoc/dochtml/internal/render.anchorTemplate *Template
var golang.org/x/pkgsite/internal/godoc/dochtml/internal/render.docDataTmpl *Template
var golang.org/x/pkgsite/internal/godoc/dochtml/internal/render.exampleTmpl *Template
A TrustedSource is an immutable string-like type referencing
trusted template files under application control. It can be passed to
template-parsing functions and methods to safely load templates
without the risk of untrusted template execution.
In order to ensure that an attacker cannot influence the TrustedSource
value, a TrustedSource can be instantiated only from untyped string
constants, command-line flags, and other application-controlled strings, but
never from arbitrary string values potentially representing untrusted user input.
Note that TrustedSource's constructors cannot truly guarantee that the
templates it references are not attacker-controlled; it can guarantee only that
the path to the template itself is under application control. Users of these
constructors must ensure themselves that TrustedSource never references
attacker-controlled files or directories that contain such files.
We declare a TrustedSource not as a string but as a struct wrapping a string
to prevent construction of TrustedSource values through string conversion.
String returns the string form of the TrustedSource.
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
func TrustedSourceFromConstant(src stringConstant) TrustedSource
func TrustedSourceFromConstantDir(dir stringConstant, src TrustedSource, filename string) (TrustedSource, error)
func TrustedSourceFromEnvVar(key stringConstant) TrustedSource
func TrustedSourceFromFlag(value flag.Value) TrustedSource
func TrustedSourceJoin(elem ...TrustedSource) TrustedSource
func github.com/google/safehtml/template/uncheckedconversions.TrustedSourceFromStringKnownToSatisfyTypeContract(s string) TrustedSource
func trustedSourceRaw(s string) TrustedSource
func ParseFilesFromTrustedSources(filenames ...TrustedSource) (*Template, error)
func ParseGlobFromTrustedSource(pattern TrustedSource) (*Template, error)
func TrustedSourceFromConstantDir(dir stringConstant, src TrustedSource, filename string) (TrustedSource, error)
func TrustedSourceJoin(elem ...TrustedSource) TrustedSource
func (*Template).ParseFilesFromTrustedSources(filenames ...TrustedSource) (*Template, error)
func (*Template).ParseGlobFromTrustedSource(pattern TrustedSource) (*Template, error)
func golang.org/x/pkgsite/internal/godoc/dochtml.LoadTemplates(dir TrustedSource)
func trustedSourcesToStrings(paths []TrustedSource) []string
func golang.org/x/pkgsite/internal/frontend.parsePageTemplates(base TrustedSource) (map[string]*Template, error)
func golang.org/x/pkgsite/internal/worker.parseTemplate(staticPath, filename TrustedSource) (*Template, error)
A TrustedTemplate is an immutable string-like type containing a
safehtml/template template body. It can be safely loaded as template
text without the risk of untrusted template execution.
In order to ensure that an attacker cannot influence the TrustedTemplate
value, a TrustedTemplate can be instantiated only from untyped string constants,
and never from arbitrary string values potentially representing untrusted user input.
We declare a TrustedTemplate not as a string but as a struct wrapping a string
to prevent construction of TrustedTemplate values through string conversion.
String returns the string form of the TrustedTemplate.
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
func MakeTrustedTemplate(tmpl stringConstant) TrustedTemplate
func github.com/google/safehtml/template/uncheckedconversions.TrustedTemplateFromStringKnownToSatisfyTypeContract(s string) TrustedTemplate
func trustedTemplateRaw(s string) TrustedTemplate
func (*Template).ParseFromTrustedTemplate(tmpl TrustedTemplate) (*Template, error)
attr represents the attribute that the parser is in, that is,
starting from stateAttrName until stateTag/stateText (exclusive).
ambiguousValue indicates whether value contains an ambiguous value due to context-joining.
name is the lowercase name of the attribute. If context joining has occurred, name
will be arbitrarily assigned the attribute name from one of the joined contexts.
names contains all possible names the attribute could assume because of context joining.
For example, after joining the contexts in the "if" and "else" branches of
<a {{if .C}}title{{else}}name{{end}}="foo">
names will contain "title" and "name".
names can also contain empty strings, which represent joined contexts with no attribute name.
names will be empty if no context joining occurred.
value is the value of the attribute. If context joining has occurred, value
will be arbitrarily assigned the attribute value from one of the joined contexts.
If there are multiple actions in the attribute value, value will contain the
concatenation of all values seen so far. For example, in
<a name="foo{{.X}}bar{{.Y}}">
value is "foo" at "{{.X}}" and "foobar" at "{{.Y}}".
String returns the string representation of the attr.
eq reports whether a and b have the same name. All other fields are ignored.
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
context describes the state an HTML parser must be in when it reaches the
portion of HTML produced by evaluating a particular template node.
The zero value of type Context is the start context for a template that
produces an HTML fragment as defined at
http://www.w3.org/TR/html5/syntax.html#the-end
where the context element is null.
attrattrdelimdelimelementelementerr*Error
linkRel is the value of the "rel" attribute inside the current "link"
element (see https://html.spec.whatwg.org/multipage/semantics.html#attr-link-rel).
This value has been normalized to lowercase with exactly one space between tokens
and exactly one space at start and end, so that a lookup of any token foo can
be performed by searching for the substring " foo ".
This field will be empty if the parser is currently not in a link element,
the rel attribute has not already been parsed in the current element, or if the
value of the rel attribute cannot be determined at parse time.
scriptType is the lowercase value of the "type" attribute inside the current "script"
element (see https://dev.w3.org/html5/spec-preview/the-script-element.html#attr-script-type).
This field will be empty if the parser is currently not in a script element,
the type attribute has not already been parsed in the current element, or if the
value of the type attribute cannot be determined at parse time.
statestate
eq returns whether Context c is equal to Context d.
func contextAfterText(c context, s []byte) (context, int)
func join(a, b context, node parse.Node, nodeName string) context
func nudge(c context) context
func tAfterName(c context, s []byte) (context, int)
func tAttr(c context, s []byte) (context, int)
func tAttrName(c context, s []byte) (context, int)
func tBeforeValue(c context, s []byte) (context, int)
func tError(c context, s []byte) (context, int)
func tHTMLCmt(c context, s []byte) (context, int)
func tSpecialTagEnd(c context, s []byte) (context, int)
func tTag(c context, s []byte) (context, int)
func tText(c context, s []byte) (context, int)
func contextAfterText(c context, s []byte) (context, int)
func join(a, b context, node parse.Node, nodeName string) context
func mangle(c context, templateName string) string
func nudge(c context) context
func sanitizerForContext(c context) ([]string, error)
func sanitizerForElementContent(c context) (string, error)
func sanitizersForAttributeValue(c context) ([]string, error)
func tAfterName(c context, s []byte) (context, int)
func tAttr(c context, s []byte) (context, int)
func tAttrName(c context, s []byte) (context, int)
func tBeforeValue(c context, s []byte) (context, int)
func tError(c context, s []byte) (context, int)
func tHTMLCmt(c context, s []byte) (context, int)
func tSpecialTagEnd(c context, s []byte) (context, int)
func tTag(c context, s []byte) (context, int)
func tText(c context, s []byte) (context, int)
name is the lowercase name of the element. If context joining has occurred, name
will be arbitrarily assigned the element name from one of the joined contexts.
names contains all possible names the element could assume because of context joining.
For example, after joining the contexts in the "if" and "else" branches of
{{if .C}}<img{{else}}<audio{{end}} src="/some/path">`,
names will contain "img" and "audio".
names can also contain empty strings, which represent joined contexts with no element name.
names will be empty if no context joining occurred.
String returns the string representation of the element.
eq reports whether a and b have the same name. All other fields are ignored.
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
func eatTagName(s []byte, i int) (int, element)
escaper collects type inferences about templates and changes needed to make
templates injection safe.
xxxNodeEdits are the accumulated edits to apply during commit.
Such edits are not applied immediately in case a template set
executes a given template in different escaping contexts.
called[templateName] is a set of called mangled template names.
derived[c.mangle(name)] maps to a template derived from the template
named name templateName for the start context c.
ns is the nameSpace that this escaper is associated with.
output[templateName] is the output context for a templateName that
has been mangled to include its input context.
templateNodeEditsmap[*parse.TemplateNode]stringtextNodeEditsmap[*parse.TextNode][]byte
arbitraryTemplate returns an arbitrary template from the name space
associated with e and panics if no templates are found.
commit applies changes to actions and template calls needed to contextually
autoescape content and adds any derived templates to the set.
computeOutCtx takes a template and its start context and computes the output
context while storing any inferences in e.
editActionNode records a change to an action pipeline for later commit.
editTemplateNode records a change to a {{template}} callee for later commit.
editTextNode records a change to a text node for later commit.
escape escapes a template node.
escapeAction escapes an action template node.
escapeBranch escapes a branch template node: "if", "range" and "with".
escapeList escapes a list template node.
escapeListConditionally escapes a list node but only preserves edits and
inferences in e if the inferences and output context satisfy filter.
It returns the best guess at an output context, and the result of the filter
which is the same as whether e was updated.
escapeTemplate escapes a {{template}} call node.
escapeTemplateBody escapes the given template assuming the given output
context, and returns the best guess at the output context and whether the
assumption was correct.
escapeText escapes a text template node.
escapeTree escapes the named template starting in the given context as
necessary and returns its output context.
template returns the named template given a mangled template name.
func makeEscaper(n *nameSpace) escaper
nameSpace is the data structure shared by all templates in an association.
cspCompatible indicates whether inline event handlers and
javascript: URIs are disallowed in templates in this namespace.
escescaperescapedboolmusync.Mutexsetmap[string]*Template
func makeEscaper(n *nameSpace) escaper
sanitizationContext determines what type of sanitization to perform
on a template action.
String returns the string representation of sanitizationContext s.
isEnum reports reports whether s is a sanitization context for enumerated values.
isURLorTrustedResourceURL reports reports whether s is a sanitization context for URL or TrustedResourceURL values.
sanitizerName returns the name of the sanitizer to call in sanitizationContext s.
It returns an empty string if no sanitization is required in s.
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
func sanitizationContextForAttrVal(element, attr, linkRel string) (sanitizationContext, error)
func sanitizationContextForElementContent(element string) (sanitizationContext, error)
state describes a high-level HTML parser state.
It bounds the top of the element stack, and by extension the HTML insertion
mode, but also contains state that does not correspond to anything in the
HTML5 parsing algorithm because a single token production in the HTML
grammar may contain embedded actions in a template. For instance, the quoted
HTML attribute produced by
<div title="Hello {{.World}}">
is a single token in HTML's grammar but in a template spans several nodes.
( T) String() string
T : expvar.Var
T : fmt.Stringer
T : context.stringer
T : runtime.stringer
func isComment(s state) bool
func isInTag(s state) bool
const stateAfterName
const stateAttr
const stateAttrName
const stateBeforeValue
const stateError
const stateHTMLCmt
const stateSpecialElementBody
const stateTag
const stateText
Package-Level Functions (total 83, in which 14 are exported)
IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
and whether the value has a meaningful truth value. This is the definition of
truth used by if and other such actions.
MakeTrustedTemplate constructs a TrustedTemplate with its underlying
tmpl set to the given tmpl, which must be an untyped string constant.
No runtime validation or sanitization is performed on tmpl; being under
application control, it is simply assumed to comply with the TrustedTemplate type
contract.
Must is a helper that wraps a call to a function returning (*Template, error)
and panics if the error is non-nil. It is intended for use in variable initializations
such as
var t = template.Must(template.New("name").Parse("html"))
MustParseAndExecuteToHTML is a helper that returns the safehtml.HTML value produced
by parsing text as a template body and executing it with no data. Any errors
encountered parsing or executing the template are fatal. This function is intended
to produce safehtml.HTML values from static HTML snippets such as
html := MustParseAndExecuteToHTML("<b>Important</b>")
To guarantee that the template body is never controlled by an attacker, text
must be an untyped string constant, which is always under programmer control.
New allocates a new HTML template with the given name.
ParseFiles creates a new Template and parses the template definitions from
the named files. The returned template's name will have the (base) name and
(parsed) contents of the first file. There must be at least one file.
If an error occurs, parsing stops and the returned *Template is nil.
When parsing multiple files with the same name in different directories,
the last one mentioned will be the one that results.
For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
named "foo", while "a/foo" is unavailable.
To guarantee that filepaths, and thus template bodies, are never controlled by
an attacker, filenames must be untyped string constants, which are always under
programmer control.
ParseFilesFromTrustedSources creates a new Template and parses the template definitions from
the named files. The returned template's name will have the (base) name and
(parsed) contents of the first file. There must be at least one file.
If an error occurs, parsing stops and the returned *Template is nil.
When parsing multiple files with the same name in different directories,
the last one mentioned will be the one that results.
For instance, ParseFiles("a/foo", "b/foo") stores "b/foo" as the template
named "foo", while "a/foo" is unavailable.
To guarantee that filepaths, and thus template bodies, are never controlled by
an attacker, filenames must be trusted sources, which are always under programmer
or application control.
ParseGlob creates a new Template and parses the template definitions from the
files identified by the pattern, which must match at least one file. The
returned template will have the (base) name and (parsed) contents of the
first file matched by the pattern. ParseGlob is equivalent to calling
ParseFiles with the list of files matched by the pattern.
To guarantee that the pattern, and thus the template bodies, is never controlled by
an attacker, pattern must be an untyped string constant, which is always under
programmer control.
ParseGlobFromTrustedSource creates a new Template and parses the template definitions from the
files identified by the pattern, which must match at least one file. The
returned template will have the (base) name and (parsed) contents of the
first file matched by the pattern. ParseGlobFromTrustedSource is equivalent to calling
ParseFilesFromTrustedSources with the list of files matched by the pattern.
To guarantee that the pattern, and thus the template bodies, is never controlled by
an attacker, pattern must be a trusted source, which is always under programmer or
application control.
TrustedSourceFromConstant constructs a TrustedSource with its underlying
src set to the given src, which must be an untyped string constant.
No runtime validation or sanitization is performed on src; being under
application control, it is simply assumed to comply with the TrustedSource type
contract.
TrustedSourceFromConstantDir constructs a TrustedSource calling path/filepath.Join on
an application-controlled directory path, which must be an untyped string constant,
a TrustedSource, and a dynamic filename. It returns an error if filename contains
filepath or list separators, since this might cause the resulting path to reference a
file outside of the given directory.
dir or src may be empty if either of these path segments are not required.
TrustedSourceFromEnvVar is a wrapper around os.Getenv that
returns a TrustedSource containing the value of the environment variable
named by the key. It returns the value, which will be empty if the variable
is not present. To distinguish between an empty value and an unset value,
use os.LookupEnv.
In a server setting, environment variables are part of the application's
deployment configuration and are hence considered application-controlled.
TrustedSourceFromFlag returns a TrustedSource containing the string
representation of the retrieved value of the flag.
In a server setting, flags are part of the application's deployment
configuration and are hence considered application-controlled.
TrustedSourceJoin is a wrapper around path/filepath.Join that returns a
TrustedSource formed by joining the given path elements into a single path,
adding an OS-specific path separator if necessary.
appendIfNotEmpty appends the given strings that are non-empty to the given slice.
asciiAlpha reports whether c is an ASCII letter.
asciiAlphaNum reports whether c is an ASCII letter or digit.
s is a JS template string (without the opening `); this function consumes s up to
the matching closing `.
s is a Js Template expression (starting with "${"). This function consumes up to and including the matching closing "}".
contextAfterText starts in context c, consumes some tokens from the front of
s, then returns the context after those tokens and the unprocessed suffix.
decodeURLPrefix returns the given prefix after it has been HTML-unescaped.
It returns an error if the prefix:
* ends in an incomplete HTML character reference before HTML-unescaping,
* ends in an incomplete percent-encoding character triplet after HTML-unescaping, or
* contains whitespace before or after HTML-unescaping.
eatAttrName returns the largest j such that s[i:j] is an attribute name.
It returns an error if s[i:] does not look like it begins with an
attribute name, such as encountering a quote mark without a preceding
equals sign.
eatTagName returns the largest j such that s[i:j] is a tag name and the tag name.
eatWhiteSpace returns the largest j such that s[i:j] is white space.
ensurePipelineContains ensures that the pipeline ends with the commands with
the identifiers in s in order. If the pipeline ends with a predefined escaper
(i.e. "html" or "urlquery"), merge it with the identifiers in s.c
errorf creates an error given a format string f and args.
The template Name still needs to be supplied.
escapeTemplate rewrites the named template, which must be
associated with t, to guarantee that the output of any of the named
templates is properly escaped. If no error is returned, then the named templates have
been modified. Otherwise the named templates have been rendered
unusable.
escFnsEq reports whether the two escaping functions are equivalent.
evalArgs formats the list of arguments into a string. It is equivalent to
fmt.Sprint(args...), except that it deferences all pointers.
indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1
indirectToStringerOrError returns the value, after dereferencing as many times
as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
or error,
isComment reports whether a state contains content meant for template
authors & maintainers, not for end-users or machines.
isInTag reports whether s occurs solely inside an HTML tag.
Determine if a string has unbalanced (open) JS templates.
join joins the two contexts of a branch template node. The result is an
error context if either of the input contexts are error contexts, or if the
input contexts differ.
joinNames returns the slice of all possible names that an element or attr could
assume after context joining the element or attr containing aName and aNames with the
element or attr containing bName and bNames.
makeEscaper creates a blank escaper for the given set.
mangle produces an identifier that includes a suffix that distinguishes it
from template names mangled with different contexts.
newIdentCmd produces a command containing a single identifier node.
normalizeEscFn(a) is equal to normalizeEscFn(b) for any pair of names of
escaper functions a and b that are equivalent.
nudge returns the context that would result from following empty string
transitions from the input context.
For example, parsing:
`<a href=`
will end in context{stateBeforeValue, AttrURL}, but parsing one extra rune:
`<a href=x`
will end in context{stateURL, delimSpaceOrTagEnd, ...}.
There are two transitions that happen when the 'x' is seen:
(1) Transition from a before-value state to a start-of-value state without
consuming any character.
(2) Consume 'x' and transition past the first value character.
In this case, nudging produces the context after (1) happens.
parseFiles is the helper for the method and function. If the argument
template is nil, it is created from the first file.
parseGlob is the implementation of the function and method ParseGlob.
reverse reverses s and returns it.
sanitizationContextForAttrVal returns the sanitization context for attr when it
appears within element.
sanitizationContextForElementContent returns the element content sanitization context for the given element.
sanitizeHTMLComment returns the empty string regardless of input.
Comment content does not correspond to any parsed structure or
human-readable content, so the simplest and most secure policy is to drop
content interpolated into comments.
This approach is equally valid whether or not static comment content is
removed from the template.
sanitizerForContext returns an ordered list of function names that will be called to
sanitize data values found in the HTML context defined by c.
sanitizerForElementContent returns the name of the function that will be called
to sanitize data values found in the HTML element content context c.
sanitizersForAttributeValue returns a list of names of functions that will be
called in order to sanitize data values found the HTML attribtue value context c.
tSpecialTagEnd is the context transition function for raw text, RCDATA
script data, and stylesheet element states.
tTag is the context transition function for the tag state.
tText is the context transition function for the text state.
validateDoesNotEndsWithCharRefPrefix returns an error only if the given prefix ends
with an incomplete HTML character reference.
validateTrustedResourceURLPrefix validates if the given non-empty prefix is a safe
safehtml.TrustedResourceURL prefix.
Prefixes are considered unsafe if they end in an incomplete HTML character reference
or percent-encoding character triplet.
See safehtmlutil.IsSafeTrustedResourceURLPrefix for details on how the prefix is validated.
validateURLPrefix validates if the given non-empty prefix is a safe safehtml.URL prefix.
Prefixes are considered unsafe if they end in an incomplete HTML character reference
or percent-encoding character triplet.
If the prefix contains a fully-specified scheme component, it is considered safe only if
it starts with a whitelisted scheme. See safehtml.URLSanitized for more details.
Otherwise, the prefix is safe only if it contains '/', '?', or '#', since the presence of any
of these runes ensures that this prefix, when combined with some arbitrary suffix, cannot be
interpreted as a part of a scheme.
Package-Level Variables (total 36, none are exported)
containsWhitespaceOrControlPattern matches strings that contain ASCII whitespace
or control characters.
dataAttributeNamePattern matches valid data attribute names.
This pattern is conservative and matches only a subset of the valid names defined in
https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes
delimEnds maps each delim to a string of characters that terminate it.
elementContentSanitizationContext maps element names to element content sanitization contexts.
elementSpecificAttrValSanitizationContext[x][y] is the sanitization context for
attribute x when it appears within element y.
endsWithCharRefPrefixPattern matches strings that end in an incomplete
HTML character reference.
See https://html.spec.whatwg.org/multipage/syntax.html#character-references.
endsWithPercentEncodingPrefixPattern matches strings that end in an incomplete
URL percent encoding triplet.
See https://tools.ietf.org/html/rfc3986#section-2.1.
equivEscapers matches contextual escapers to equivalent predefined
template escapers.
errEscapeOK is a sentinel value used to indicate valid escaping.
globalAttrValSanitizationContext[x] is the sanitization context for attribute x when
it appears within any element not in the key set of elementSpecificAttrValSanitizationContext[x].
predefinedEscapers contains template predefined escapers that are equivalent
to some contextual escapers. Keep in sync with equivEscapers.
sanitizationContextInfo[x] contains the name for sanitization context x and the
name of the sanitizer to call in that context.
If sanitizationContextInfo[x].sanitizerName is empty, then no sanitizer needs
to be called in x.
transitionFunc is the array of context transition functions for text nodes.
A transition function takes a context and template text input, and returns
the updated context and the number of bytes consumed from the front of the
input.
urlLinkRelVals contains values for a link element's rel attribute that indicate that the same link
element's href attribute may contain a safehtml.URL value.
urlPrefixValidators maps URL and TrustedResourceURL sanitization contexts to functions return an error
if the given string is unsafe to use as a URL prefix in that sanitization context.
voidElements contains the names of all void elements.
https://www.w3.org/TR/html5/syntax.html#void-elements
Package-Level Constants (total 67, in which 15 are exported)
ErrAmbigContext: "... appears in an ambiguous context within a URL"
Example:
<a href="
{{if .C}}
/path/
{{else}}
/search?q=
{{end}}
{{.X}}
">
Discussion:
{{.X}} is in an ambiguous URL context since, depending on {{.C}},
it may be either a URL suffix or a query parameter.
Moving {{.X}} into the condition removes the ambiguity:
<a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}">
ErrBadHTML: "expected space, attr name, or end of tag, but got ...",
"... in unquoted attr", "... in attribute name"
Example:
<a href = /search?q=foo>
<href=foo>
<form na<e=...>
<option selected<
Discussion:
This is often due to a typo in an HTML element, but some runes
are banned in tag names, attribute names, and unquoted attribute
values because they can tickle parser ambiguities.
Quoting all attributes is the best policy.
ErrBranchEnd: "{{if}} branches end in different contexts"
Example:
{{if .C}}<a href="{{end}}{{.X}}
Discussion:
Package html/template statically examines each path through an
{{if}}, {{range}}, or {{with}} to escape any following pipelines.
The example is ambiguous since {{.X}} might be an HTML text node,
or a URL prefix in an HTML attribute. The context of {{.X}} is
used to figure out how to escape it, but that context depends on
the run-time value of {{.C}} which is not statically known.
The problem is usually something like missing quotes or angle
brackets, or can be avoided by refactoring to put the two contexts
into different branches of an if, range or with. If the problem
is in a {{range}} over a collection that should never be empty,
adding a dummy {{else}} can help.
ErrCSPCompatibility: `"javascript:" URI disallowed for CSP compatibility`,
"inline event handler ... is disallowed for CSP compatibility
Examples:
<span onclick="doThings();">A thing.</span>
<a href="javascript:linkClicked()">foo</a>
Discussion:
Inline event handlers (onclick="...", onerror="...") and
<a href="javascript:..."> links can be used to run scripts,
so an attacker who finds an XSS bug could inject such HTML
and execute malicious JavaScript. These patterns must be
refactored into safer alternatives for compatibility with
Content Security Policy (CSP).
For example, the following HTML that contains an inline event handler:
<script> function doThings() { ... } </script>
<span onclick="doThings();">A thing.</span>
can be refactored into:
<span id="things">A thing.</span>
<script nonce="${nonce}">
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('things')
.addEventListener('click', function doThings() { ... });
});
</script>
Likewise, the following HTML containng a javascript: URI:
<a href="javascript:linkClicked()">foo</a>
can be refactored into:
<a id="foo">foo</a>
<script nonce="${nonce}">
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('foo')
.addEventListener('click', linkClicked);
});
</script>
ErrEndContext: "... ends in a non-text context: ..."
Examples:
<div
<div title="no close quote>
<script>f()
Discussion:
Executed templates should produce a DocumentFragment of HTML.
Templates that end without closing tags will trigger this error.
Templates that should not be used in an HTML context or that
produce incomplete Fragments should not be executed directly.
{{define "main"}} <script>{{template "helper"}}</script> {{end}}
{{define "helper"}} document.write(' <div title=" ') {{end}}
"helper" does not produce a valid document fragment, so should
not be Executed directly.
ErrEscapeAction: "cannot escape action ..."
Discussion:
Error returned while escaping an action using EscaperForContext.
Refer to error message for more details.
TODO: remove this error type and replace it with more informative sanitization errors.
ErrNoSuchTemplate: "no such template ..."
Examples:
{{define "main"}}<div {{template "attrs"}}>{{end}}
{{define "attrs"}}href="{{.URL}}"{{end}}
Discussion:
Package html/template looks through template calls to compute the
context.
Here the {{.URL}} in "attrs" must be treated as a URL when called
from "main", but you will get this error if "attrs" is not defined
when "main" is parsed.
ErrOutputContext: "cannot compute output context for template ..."
Examples:
{{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}}
Discussion:
A recursive template does not end in the same context in which it
starts, and a reliable output context cannot be computed.
Look for typos in the named template.
If the template should not be called in the named start context,
look for calls to that template in unexpected contexts.
Maybe refactor recursive templates to not be recursive.
ErrPartialCharset: "unfinished JS regexp charset in ..."
Example:
<script>var pattern = /foo[{{.Chars}}]/</script>
Discussion:
Package html/template does not support interpolation into regular
expression literal character sets.
ErrPartialEscape: "unfinished escape sequence in ..."
Example:
<script>alert("\{{.X}}")</script>
Discussion:
Package html/template does not support actions following a
backslash.
This is usually an error and there are better solutions; for
example
<script>alert("{{.X}}")</script>
should work, and if {{.X}} is a partial escape sequence such as
"xA0", mark the whole sequence as safe content: JSStr(`\xA0`)
ErrPredefinedEscaper: "predefined escaper ... disallowed in template"
Example:
<div class={{. | html}}>Hello<div>
Discussion:
Package html/template already contextually escapes all pipelines to
produce HTML output safe against code injection. Manually escaping
pipeline output using the predefined escapers "html" or "urlquery" is
unnecessary, and may affect the correctness or safety of the escaped
pipeline output in Go 1.8 and earlier.
In most cases, such as the given example, this error can be resolved by
simply removing the predefined escaper from the pipeline and letting the
contextual autoescaper handle the escaping of the pipeline. In other
instances, where the predefined escaper occurs in the middle of a
pipeline where subsequent commands expect escaped input, e.g.
{{.X | html | makeALink}}
where makeALink does
return `<a href="`+input+`">link</a>`
consider refactoring the surrounding template to make use of the
contextual autoescaper, i.e.
<a href="{{.X}}">link</a>
To ease migration to Go 1.9 and beyond, "html" and "urlquery" will
continue to be allowed as the last command in a pipeline. However, if the
pipeline occurs in an unquoted attribute value context, "html" is
disallowed. Avoid using "html" and "urlquery" entirely in new templates.
ErrRangeLoopReentry: "on range loop re-entry: ..."
Example:
<script>var x = [{{range .}}'{{.}},{{end}}]</script>
Discussion:
If an iteration through a range would cause it to end in a
different context than an earlier pass, there is no single context.
In the example, there is missing a quote, so it is not clear
whether {{.}} is meant to be inside a JS string or in a JS value
context. The second iteration would produce something like
<script>var x = ['firstValue,'secondValue]</script>
ErrSlashAmbig: '/' could start a division or regexp.
Example:
<script>
{{if .C}}var x = 1{{end}}
/-{{.N}}/i.test(x) ? doThis : doThat();
</script>
Discussion:
The example above could produce `var x = 1/-2/i.test(s)...`
in which the first '/' is a mathematical division operator or it
could produce `/-2/i.test(s)` in which the first '/' starts a
regexp literal.
Look for missing semicolons inside branches, and maybe add
parentheses to make it clear which interpretation you intend.
All JS templates inside script literals have to be balanced; otherwise a concatenation such as
<script>alert(`x{{.data}}`</script> can contain XSS if data contains user-controlled escaped strings (e.g. as JSON).
stateAfterName occurs after an attr name has ended but before any
equals sign. It occurs between the ^'s in ` name^ ^= value`.
stateAttr occurs inside an HTML attribute whose content is text.
stateAttrName occurs inside an attribute name.
It occurs between the ^'s in ` ^name^ = value`.
stateBeforeValue occurs after the equals sign but before the value.
It occurs between the ^'s in ` name =^ ^value`.
stateError is an infectious error state outside any valid
HTML/CSS/JS construct.
stateHTMLCmt occurs inside an <!-- HTML comment -->.
stateSpecialElementBody occurs inside a specal HTML element body.
stateTag occurs before an HTML attribute or the end of a tag.
stateText is parsed character data. An HTML parser is in
this state when its parse position is outside an HTML tag,
directive, comment, and special element body.
testNilEmptySliceDataNilWant is the expected value for the "nil" test case in
TestNilEmptySliceData.
nil is printed as `<nil>` by text/template in Go 1.11, which then gets HTML-escaped
by safehtml/template to `<nil>`.
The pages are generated with Goldsv0.3.2-preview. (GOOS=darwin GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.