Frontend Security: Applying Contextual Escaping Automatically, or How to Stop XSS in Seconds
1. Frontend Security: Applying Contextual Escaping Automatically, or
How to Stop XSS in Seconds
PRESENTED BY Nera Liu and Adonis Fung⎪ May 21, 2015
2. Problem Statement
What makes XSS prevention so hard?
Background > Related Work > Our Approach > Evaluations > Conclusion
3. XSS Quick Explanation
Given no proper output filtering:
<h1>Hello <?php echo $_GET['name']; ?></h1>
An attack vector can come through the query string
at victim.com/?name=XXX, where XXX is:
"'><script>alert(1)</script>
HTML of victim.com ends up being:
<h1>Hello "'><script>alert(1)</script></h1>
4. Cross-Site Scripting (XSS)
Root Cause
- Untrusted inputs executed as scripts under a victim’s origin/domain
Consequences
- Cookie stealing, privacy leaking
- Fully control the web content
- Bug bounty costs
5. Cross-Site Scripting (XSS)
■ Ranked No. 3 / OWASP Top 10 WebApp Security Risks
Screen-captured from https://www.owasp.org/index.php/Top_10_2013-A3-Cross-Site_Scripting_(XSS)
7. Blindly-escaping is still vulnerable!
Blindly-escaping (&<>"'`) would not stop XSS, when
- {{url}} is an untrusted user input (assumed thereafter)
- {{url}} is javascript:alert(1), or
- {{url}} is # onclick=alert(1)
→ We need Contextual Escaping!
- While blindlyEscape( data ) works, but not for url
- blacklistProtocol( escapeUnquoted ( encodeURI( url ) ) )
A template is typically written like so:
<a href={{url}}>{{data}}</a>
9. Related Work
Limited solutions/attempts available
- Use Closure/AngularJS w/Strict Contextual Escaping
- Use XML Templates with Java/JSP
- Without Contextual Escaping: React, Dust, etc...
Deployability/Adoption Issues
- Framework specific
- Browser compatibility issues
- Not for existing projects, unless requiring many code changes
10. Highlights
- Efficient HTML 5 compliant parser w/auto corrections
- Auto apply contextual, just-sufficient, and faster escaping
- Effortless adoption requiring as little as 2 LoC changes
https://yahoo.github.io/secure-handlebars
Our Approach: Secure Handlebars
Automatic contextual escaping made easy
11. Handlebars
Context Parser
Handlebars PreProcessor
High-level Architecture
Template
Parser
Template
AST
HTML5 Parser
(w/auto corrections)
JS Parser
AST
Walker
Template
w/filter markups
abstracting branching logics and output expressions
CSS Parser
Pre-
compiler
Contextual XSS Filters
(registered as helpers/callbacks)
HTML
Data
(possibly untrusted)
Runtime
Compiler
Template
Spec.
Our solution comprises of only the blue boxes
12. Handlebars
Context Parser
Handlebars PreProcessor
High-level Architecture
Template
Parser
Template
AST
HTML5 Parser
(w/auto corrections)
JS Parser
AST
Walker
Template
w/filter markups
abstracting branching logics and output expressions
CSS Parser
Pre-
compiler
Contextual XSS Filters
(registered as helpers/callbacks)
HTML
Data
(possibly untrusted)
Runtime
Compiler
Template
Spec.
Our solution comprises of only the blue boxes
13. Pre-Processor: Good Template Samples
[Before]
<a href="{{url}}">{{url}}</a>
[After]
<a href="{{{yubl (yavd (yufull url))}}}">{{{yd url}}}</a>
Add contextual escaping filters
{{{ }}} - disable the default blindly-escaping
yufull - encodeURI()with IPv6 support
yavd - html-escape double-quote character (" → ")
yubl - disable dangerous protocols such as javascript:
yd - html-escape less-than character (< → <)
14. Pre-Processor: Bad Template Samples
[Before]
<input type="button" onclick="doSth({{data}})">
Warning!
Ensure placeholders are never put in scriptable contexts
- Security anti-pattern to place (possibly) untrusted data in executable contexts
- Workaround:
- <input type="button" data-sth="{{data}}"
onclick="doSth(this.getAttribute('data-sth'))">
15. Pre-Processor: Branching Consistency Check
[Before]
{{#if highlight}}<strong>{{else}}<em {{/if}} {{unknownCxt}} ...
[After] A warning is raised!
{{#if highlight}}<strong>{{else}}<em {{/if}} {{data}} ...
Walk through branches & ensure they end up in identical state/context
- Likely a careless mistake or typo
- Obviously, context of {{unknownCxt}} is ambiguous
Warning!
16. Handlebars
Context Parser
Handlebars PreProcessor
High-level Architecture
Template
Parser
Template
AST
HTML5 Parser
(w/auto corrections)
JS Parser
AST
Walker
Template
w/filter markups
abstracting branching logics and output expressions
CSS Parser
Pre-
compiler
Contextual XSS Filters
(registered as helpers/callbacks)
HTML
Data
(possibly untrusted)
Runtime
Compiler
Template
Spec.
Our solution comprises of only the blue boxes
17. Standard Compliant
- Can even auto-correct parse errors to enforce
consistent parsing across browsers
Robust, lightweight, and efficient
- Simplified state transitions
- No unnecessary handling (no DOM)
Design Principles of Context Parser
Figured from Overview of HTML 5 Parsing Model: https://html.spec.whatwg.org/multipage/syntax.html#overview-of-the-parsing-model
18. Handlebars
Context Parser
Handlebars PreProcessor
High-level Architecture
Template
Parser
Template
AST
HTML5 Parser
(w/auto corrections)
JS Parser
AST
Walker
Template
w/filter markups
abstracting branching logics and output expressions
CSS Parser
Pre-
compiler
Contextual XSS Filters
(registered as helpers/callbacks)
HTML
Data
(possibly untrusted)
Runtime
Compiler
Template
Spec.
Our solution comprises of all blue boxes
19. Design Principles of XSS Filters
Context-aware
- More Secure - escape only
those that can break out
from its context
Just sufficient encoding
- Faster - no need to
escape all & > " ' `
- More friendly - no more
double-encoding issues like
&lt;
20. Deployability
Adoption
- Switch from express-handlebars to express-secure-handlebars npm
- 2 LOCs changes: (1) dependency in package.json, (2) require(...)
- Alternatively, a more decoupled approach:
- pre-process tmpl to get it rewrited during build process at server
- only register helpers for data filtering and binding at client-side
Browser Compatibility
- IE 7+, Safari 5+, Chrome, Firefox
21. Evaluations
Deployed in one the largest properties
- Negligible offline overhead
- takes <3s to analyze/pre-process 880 templates
- Insignifiant runtime overhead (i.e., filter callbacks, size: 1.3KB gz)
- unchained filters: up to 2 times faster than default
- chained filters: slower but is already minimal to be secure
- True positives found!
- e.g., unquoted, onclick, URI attributes, script tags, etc.
22. - More secure, efficient, and easier adoption
- Open-sourced at github.com/yahoo and npmjs.com
- Contact/Collaborate with us for more template support
Conclusion: Building A Safer Internet for All
Automatic contextual escaping made easy