AngularJS Strict Contextual Escaping ($sce)

19
$SCE ANGULARJS

description

What is $sce and how do I use it? Why did Angular eliminate ng-bind-html-unsafe? How can I emulate the old behavior? How can I do better than emulating the old behavior of html binding? Presented at the Seattle AngularJS Meetup on March 19, 2014 - http://www.meetup.com/AngularJS-SEA/events/169192362/

Transcript of AngularJS Strict Contextual Escaping ($sce)

Page 1: AngularJS Strict Contextual Escaping ($sce)

$ S C EA N G U L A R J S

Page 2: AngularJS Strict Contextual Escaping ($sce)

J o s h S c h u m a c h e r

@ j o s h s c h u m a c h e r h t t p s : / / p l u s . g o o g l e . c o m / + J o s h S c h u m a c h e r s

H a s O f f e r s

Page 3: AngularJS Strict Contextual Escaping ($sce)

S T R I C T C O N T E X T U A L E S C A P I N G

Page 4: AngularJS Strict Contextual Escaping ($sce)

– N O O N E E V E R

“We can trust our users and the input they provide.”

Page 5: AngularJS Strict Contextual Escaping ($sce)

A N G U L A R 1 . 0 . 8

• ng-bind

• ng-bind-html

• ng-bind-html-unsafe

<script> function snippetController($scope) { $scope.snippet = '<p style="color:blue">\n an html\n' + ' <em onmouseover="this.textContent=\'PWN3D!\'">click here</em>' + ' snippet\n</p>'; } </script> !<div ng-controller="snippetController" class="container"> <form> <h1>User Input</h1> <textarea class="form-control" rows="4" ng-model="snippet"></textarea> </form> ! <h2>ng-bind</h2> <pre ng-bind="snippet"></pre> !! <h2>ng-bind-html</h2> <div ng-bind-html="snippet"></div> !! <h2>ng-bind-html-unsafe</h2> <div ng-bind-html-unsafe="snippet"></div> !</div>

Demo…

Page 6: AngularJS Strict Contextual Escaping ($sce)

G O O D B Y E N G - B I N D - H T M L - U N S A F E

Page 7: AngularJS Strict Contextual Escaping ($sce)

A N G U L A R 1 . 2

• ng-bind

• ng-bind-html

• ng-bind-html-unsafe

<script> function snippetController($scope) { $scope.snippet = '<p style="color:blue">\n an html\n' + ' <em onmouseover="this.textContent=\'PWN3D!\'">click here</em>' + ' snippet\n</p>'; } </script> !<div ng-controller="snippetController" class="container"> <form> <h1>User Input</h1> <textarea class="form-control" rows="4" ng-model="snippet"></textarea> </form> ! <h2>ng-bind</h2> <pre ng-bind="snippet"></pre> !! <h2>ng-bind-html</h2> <div ng-bind-html="snippet"></div> !</div>

Page 8: AngularJS Strict Contextual Escaping ($sce)

Y O U ’ R E N O T T H AT L U C K Y

Error: [$sce:unsafe] http://errors.angularjs.org/1.2.14/$sce/unsafe at Error (native) at http://code.angularjs.org/1.2.14/angular.min.js:6:450 at e (http://code.angularjs.org/1.2.14/angular.min.js:110:34) at getTrusted (http://code.angularjs.org/1.2.14/angular.min.js:111:327) at Object.e.(anonymous function) [as getTrustedHtml] (http://code.angularjs.org/1.2.14/angular.min.js:113:71) at Object.fn (http://code.angularjs.org/1.2.14/angular.min.js:182:71) at h.$digest (http://code.angularjs.org/1.2.14/angular.min.js:102:370) at h.$apply (http://code.angularjs.org/1.2.14/angular.min.js:105:173) at http://code.angularjs.org/1.2.14/angular.min.js:18:23 at Object.d [as invoke] (http://code.angularjs.org/1.2.14/angular.min.js:30:452)

Page 9: AngularJS Strict Contextual Escaping ($sce)

L O N G L I V E n g S A N I T I Z E

var app = angular.module('myApp', ['ngSanitize']);

<script src="http://code.angularjs.org/1.2.14/angular-sanitize.min.js"></script>

Demo…

Page 10: AngularJS Strict Contextual Escaping ($sce)

var ngBindHtmlDirective = ['$sce', function($sce) { return function(scope, element, attr) { scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) { element.html($sce.getTrustedHtml(value) || ''); }); }; }];

Bread and Butter<div ng-bind-html="snippet"></div>

Page 11: AngularJS Strict Contextual Escaping ($sce)

$sce.getTrustedHtml(value);

→ $sceDelegate.getTrusted($sce.HTML, value)

→ $sceDelegate.getTrusted($sce.URL, value)

→ $sceDelegate.getTrusted($sce.RESOURCE_URL, value)

→ $sceDelegate.getTrusted($sce.JS, value)

→ $sceDelegate.getTrusted($sce.CSS, value)

Page 12: AngularJS Strict Contextual Escaping ($sce)

var ngBindHtmlDirective = ['$sce', function($sce) { return function(scope, element, attr) { scope.$watch(attr.ngBindHtml, function ngBindHtmlWatchAction(value) { element.html($sce.getTrustedHtml(value) || ''); }); }; }];

return value.$$unwrapTrustedValue();

if (type === SCE_CONTEXTS.HTML) { return htmlSanitizer(value); }

{$sceDelegate. getTrusted()

Page 13: AngularJS Strict Contextual Escaping ($sce)

S O W H Y W A S N ’ T I L U C K Y B E F O R E ?

var htmlSanitizer = function htmlSanitizer(html) { throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.'); }; !if ($injector.has('$sanitize')) { htmlSanitizer = $injector.get('$sanitize'); }

$sceDelegateProvider

Page 14: AngularJS Strict Contextual Escaping ($sce)

return value.$$unwrapTrustedValue(); ?????

var app = angular.module('myApp'); !

app.controller('snippetController', function($scope, $sce) { $scope.$watch('snippet', function(value) { $scope.snippetHarmful = $sce.trustAsHtml(value); }); });

function TrustedValueHolderType(trustedValue) { this.$$unwrapTrustedValue = function() { return trustedValue; }; };

Demo…

Page 15: AngularJS Strict Contextual Escaping ($sce)

Context Notes

$sce.HTML HTML that is safe to render in application.

$sce.CSS CSS that is safe to render in application. [currently unused by AngularJS core]

$sce.URLURLs that are safe to follow as links. <a href= and <img src= don’t use $sce [currently unused by AngularJS core]

$sce.RESOURCE_URL URLs whose contents are safe to include in your app. ng-include, ngSrc, iframe, object, etc

$sce.JS JavaScript that is safe to render in application. [currently unused by AngularJS core]

Page 16: AngularJS Strict Contextual Escaping ($sce)

C U S T O M N G - B I N D - H T M L

<h2>ng-bind-html (trusted w/ filter)</h2> <div ng-bind-html="snippet|trustedHtml"></div>

Generally a RISKY idea$scope.$watch('snippet', function(value) { value = value.replace(' onmouseover="this.textContent=\'PWN3D!\'"', ''); $scope.snippetCustomSanitized = $sce.trustAsHtml(value); });

Page 17: AngularJS Strict Contextual Escaping ($sce)

L O N G L I V E N G - B I N D - H T M L - U N S A F E

Demo…

var app = angular.module('myApp', ['ngSanitize']); !app.filter('trustedHtml', ['$sce', function($sce) { return function(value) { return $sce.trustAsHtml(value); }; }]); !

<h2>ng-bind-html (trusted w/ filter)</h2> <div ng-bind-html="snippet|trustedHtml"></div>

Generally a BAD idea

Page 18: AngularJS Strict Contextual Escaping ($sce)

C U S T O M I Z I N G T H E H T M L PA R S E R

• Not easy

• Dart recently introduced an injectable dom.NodeValidator

• Re-implement $sanitize htmlParser for global customization

• Write new htmlParser that returns $sce.trustAsHtml(parsedValue)/** * HTML Parser By Misko Hevery ([email protected]) * based on: HTML Parser By John Resig (ejohn.org) * Original code by Erik Arvidsson, Mozilla Public License */

Page 19: AngularJS Strict Contextual Escaping ($sce)

S C E R E S O U R C E _ U R L

app.config(function($sceDelegateProvider) { $sceDelegateProvider.resourceUrlWhitelist([ 'self', // Allow loading from our assets domain. Notice the difference between * and **. 'http://cdn*.assets.example.com/**' ]); }); !!!!!‘*’ matches 0 or more occurrences of any character EXCEPT ':', '/', '.', '?', '&' and ‘;' !‘**’ matches 0 or more of ANY character - be careful, generally only use at the end of a whitelist url