Home | History | Annotate | Download | only in template
      1 // Copyright 2011 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package template
      6 
      7 import (
      8 	"fmt"
      9 	"reflect"
     10 )
     11 
     12 // Strings of content from a trusted source.
     13 type (
     14 	// CSS encapsulates known safe content that matches any of:
     15 	//   1. The CSS3 stylesheet production, such as `p { color: purple }`.
     16 	//   2. The CSS3 rule production, such as `a[href=~"https:"].foo#bar`.
     17 	//   3. CSS3 declaration productions, such as `color: red; margin: 2px`.
     18 	//   4. The CSS3 value production, such as `rgba(0, 0, 255, 127)`.
     19 	// See http://www.w3.org/TR/css3-syntax/#parsing and
     20 	// https://web.archive.org/web/20090211114933/http://w3.org/TR/css3-syntax#style
     21 	//
     22 	// Use of this type presents a security risk:
     23 	// the encapsulated content should come from a trusted source,
     24 	// as it will be included verbatim in the template output.
     25 	CSS string
     26 
     27 	// HTML encapsulates a known safe HTML document fragment.
     28 	// It should not be used for HTML from a third-party, or HTML with
     29 	// unclosed tags or comments. The outputs of a sound HTML sanitizer
     30 	// and a template escaped by this package are fine for use with HTML.
     31 	//
     32 	// Use of this type presents a security risk:
     33 	// the encapsulated content should come from a trusted source,
     34 	// as it will be included verbatim in the template output.
     35 	HTML string
     36 
     37 	// HTMLAttr encapsulates an HTML attribute from a trusted source,
     38 	// for example, ` dir="ltr"`.
     39 	//
     40 	// Use of this type presents a security risk:
     41 	// the encapsulated content should come from a trusted source,
     42 	// as it will be included verbatim in the template output.
     43 	HTMLAttr string
     44 
     45 	// JS encapsulates a known safe EcmaScript5 Expression, for example,
     46 	// `(x + y * z())`.
     47 	// Template authors are responsible for ensuring that typed expressions
     48 	// do not break the intended precedence and that there is no
     49 	// statement/expression ambiguity as when passing an expression like
     50 	// "{ foo: bar() }\n['foo']()", which is both a valid Expression and a
     51 	// valid Program with a very different meaning.
     52 	//
     53 	// Use of this type presents a security risk:
     54 	// the encapsulated content should come from a trusted source,
     55 	// as it will be included verbatim in the template output.
     56 	//
     57 	// Using JS to include valid but untrusted JSON is not safe.
     58 	// A safe alternative is to parse the JSON with json.Unmarshal and then
     59 	// pass the resultant object into the template, where it will be
     60 	// converted to sanitized JSON when presented in a JavaScript context.
     61 	JS string
     62 
     63 	// JSStr encapsulates a sequence of characters meant to be embedded
     64 	// between quotes in a JavaScript expression.
     65 	// The string must match a series of StringCharacters:
     66 	//   StringCharacter :: SourceCharacter but not `\` or LineTerminator
     67 	//                    | EscapeSequence
     68 	// Note that LineContinuations are not allowed.
     69 	// JSStr("foo\\nbar") is fine, but JSStr("foo\\\nbar") is not.
     70 	//
     71 	// Use of this type presents a security risk:
     72 	// the encapsulated content should come from a trusted source,
     73 	// as it will be included verbatim in the template output.
     74 	JSStr string
     75 
     76 	// URL encapsulates a known safe URL or URL substring (see RFC 3986).
     77 	// A URL like `javascript:checkThatFormNotEditedBeforeLeavingPage()`
     78 	// from a trusted source should go in the page, but by default dynamic
     79 	// `javascript:` URLs are filtered out since they are a frequently
     80 	// exploited injection vector.
     81 	//
     82 	// Use of this type presents a security risk:
     83 	// the encapsulated content should come from a trusted source,
     84 	// as it will be included verbatim in the template output.
     85 	URL string
     86 
     87 	// Srcset encapsulates a known safe srcset attribute
     88 	// (see http://w3c.github.io/html/semantics-embedded-content.html#element-attrdef-img-srcset).
     89 	//
     90 	// Use of this type presents a security risk:
     91 	// the encapsulated content should come from a trusted source,
     92 	// as it will be included verbatim in the template output.
     93 	Srcset string
     94 )
     95 
     96 type contentType uint8
     97 
     98 const (
     99 	contentTypePlain contentType = iota
    100 	contentTypeCSS
    101 	contentTypeHTML
    102 	contentTypeHTMLAttr
    103 	contentTypeJS
    104 	contentTypeJSStr
    105 	contentTypeURL
    106 	contentTypeSrcset
    107 	// contentTypeUnsafe is used in attr.go for values that affect how
    108 	// embedded content and network messages are formed, vetted,
    109 	// or interpreted; or which credentials network messages carry.
    110 	contentTypeUnsafe
    111 )
    112 
    113 // indirect returns the value, after dereferencing as many times
    114 // as necessary to reach the base type (or nil).
    115 func indirect(a interface{}) interface{} {
    116 	if a == nil {
    117 		return nil
    118 	}
    119 	if t := reflect.TypeOf(a); t.Kind() != reflect.Ptr {
    120 		// Avoid creating a reflect.Value if it's not a pointer.
    121 		return a
    122 	}
    123 	v := reflect.ValueOf(a)
    124 	for v.Kind() == reflect.Ptr && !v.IsNil() {
    125 		v = v.Elem()
    126 	}
    127 	return v.Interface()
    128 }
    129 
    130 var (
    131 	errorType       = reflect.TypeOf((*error)(nil)).Elem()
    132 	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
    133 )
    134 
    135 // indirectToStringerOrError returns the value, after dereferencing as many times
    136 // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
    137 // or error,
    138 func indirectToStringerOrError(a interface{}) interface{} {
    139 	if a == nil {
    140 		return nil
    141 	}
    142 	v := reflect.ValueOf(a)
    143 	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
    144 		v = v.Elem()
    145 	}
    146 	return v.Interface()
    147 }
    148 
    149 // stringify converts its arguments to a string and the type of the content.
    150 // All pointers are dereferenced, as in the text/template package.
    151 func stringify(args ...interface{}) (string, contentType) {
    152 	if len(args) == 1 {
    153 		switch s := indirect(args[0]).(type) {
    154 		case string:
    155 			return s, contentTypePlain
    156 		case CSS:
    157 			return string(s), contentTypeCSS
    158 		case HTML:
    159 			return string(s), contentTypeHTML
    160 		case HTMLAttr:
    161 			return string(s), contentTypeHTMLAttr
    162 		case JS:
    163 			return string(s), contentTypeJS
    164 		case JSStr:
    165 			return string(s), contentTypeJSStr
    166 		case URL:
    167 			return string(s), contentTypeURL
    168 		case Srcset:
    169 			return string(s), contentTypeSrcset
    170 		}
    171 	}
    172 	for i, arg := range args {
    173 		args[i] = indirectToStringerOrError(arg)
    174 	}
    175 	return fmt.Sprint(args...), contentTypePlain
    176 }
    177