-
-
Notifications
You must be signed in to change notification settings - Fork 272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature request: Introduce context-aware escaping #6
Comments
URL sanitisation designSanitisation only applies to Go expressions, it wouldn't apply to constant attribute values like Users will need to migrate from using string expressions:
To using a new
To bypass sanitisation, it's possible to convert a string directly to the
This allows for compile time checks, because the Generator will be updated to generate specific code for the NotesThe sanitisation will be to check that URLs in variables are relative, or are an approved protocol. Go's built-in templating language just checks that the URL is relative, or is approved protocol (http, https, mailto): https://github.com/golang/go/blob/2ebe77a2fda1ee9ff6fd9a3e08933ad1ebaea039/src/html/template/url.go#L48 There are some useful tests that describe the sanitisation behaviour at https://golang.org/src/html/template/escape_test.go Google's safehtml package allows http, https, mailto and ftp, but also data URLs for specific MIME types: I'll do Go's set as a first pass, and might add in support for data URLs later. Bypass notesGoogle's SafeHTML package doesn't allow this sort of bypass, preferring to force a safe API surface, but Angular.js / Hugo etc. provide something similar to a Security reviewers can check for the presence of Example designpackage main
import (
"fmt"
"strings"
)
func main() {
safe := URL("/safe")
unsafe := URL("javascript:alert('hi')")
bypassedChecks := SafeURL("javascript:alert('used SafeURL to bypass sanitization')")
fmt.Println(safe)
fmt.Println(unsafe)
fmt.Println(bypassedChecks)
}
// I'm British, and use an 's' in 'sanitisation', but I use US English in code to match the Go programming language.
const FailedSanitizationURL = SafeURL("about:invalid#TemplFailedSanitizationURL")
func URL(s string) SafeURL {
//TODO: Actual checks.
if strings.HasPrefix(s, "javascript:") {
return FailedSanitizationURL
}
return SafeURL(s)
}
type SafeURL string |
Added support for URL sanitisation in: b7cfe4b I've also added a new CSS capability that applies CSS value sanitisation to all expression-generated values by default (with no option to override, because the sanitisation is sensible). I don't think it's a good idea to use a templating language to insert variables or expressions into JavaScript or CSS. It would be good to find out more about why people might be doing that and provide alternative examples. Next steps are to:
|
As a note, React currently allows unsafe strings in https://jsfiddle.net/adrianhesketh/j2bm149h/1/ This React code renders a link that results in an const Component = ({ userProvidedUrl }) => (
<div>
<h3>Secure</h3>
<a href="https://google.com">Google</a>
<h3>Insecure</h3>
<a href={ userProvidedUrl }>Google</a>
</div>
);
const host = document.querySelector("#app");
const userProvidedUrl = `javascript:alert("xss")`;
ReactDOM.render(<Component userProvidedUrl={ userProvidedUrl }/>, host);
|
CSS behaviour in ReactUnsafe CSS expressions an unsafe are automatically removed, so this code: const Component = ({ width, backgroundColor }) => (
<div>
<div style={{ width: width, backgroundColor: backgroundColor }}>Google</div>
</div>
);
const host = document.querySelector("#app");
const width = `expression(alert('1337'))`;
const red = "#ff0000";
ReactDOM.render(<Component width={width} backgroundColor={red}/>, host); Will strip the width CSS property because it contains a dangerous value. Notes on
|
I'm going to close this in favour of smaller tickets now that I've got an idea of what I want to do. For script related items:
See #23
See #24 |
templ currently uses simple escaping rules, described below:
This approach is safe when the content being applied to the
onClick
/on*
/style
, attributes andscript
/style
element contents are from trusted sources, but if not, they could become attack vectors.In most cases, developers won't be adding hyperlinks, or populating
onClick
elements from user-controlled content, but since it's a potential attack vector, it's probably worth making developers explicitly state the safety, despite the extra developer hassle.templ's element type should be aware of
href
,on*
andstyle
attributes and the contents ofscript
andstyle
tags, and automatically apply context-aware escaping improve the security posture of templ.In cases where developers need to use content (css, scripts, hyperlinks) from data that's under their control (i.e. not potentially under an attacker's control), they'll need to state that the content is "safe".
Language changes
Option 1 - New string expression operator
This could be done by adding a new context unaware string expression operator that only uses the
templ.Escape
function, rather than context-aware escaping. The syntax could be:{%!=
{%= safe
Option 2 - Force a function call to safehtml
Make the CSS, onClick etc. take appropriate types from https://github.com/google/safehtml and force users to use
safehtml.StyleFromConstant
method calls.I think this would be irritating, because it's such a long function call.
Option 3 - Wrap the function call to safehtml
Similar, to above, but create a
github.com/a-h/templ/safe
package and shorten the calls:{%= safe.Style("background-color: red") %}
{%= safe.Script("alert('hello')") %}
Decision
I don't like adding new templ expressions unless really required, so while I like option 1 (particularly the
{%!=
operator), I think option 3 is the way to go, because it's very clear what's going on even if you've never seentempl
before, and there's not many places where developers will actually need to do this (onClick
handlers, contents of<script>
tags,style
attributes).While it's potentially a breaking change for some users, we're not stable, so I think it's a good change.
The text was updated successfully, but these errors were encountered: