Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

AngularJS Strict Contextual Escaping ($sce)

16,847 views

Published on

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/

Published in: Technology

AngularJS Strict Contextual Escaping ($sce)

  1. 1. $ S C E A N G U L A R J S
  2. 2. 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 ff e r s
  3. 3. S T R I C T C O N T E X T U A L E S C A P I N G
  4. 4. – N O O N E E V E R “We can trust our users and the input they provide.”
  5. 5. 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 htmln' + ' <em onmouseover="this.textContent='PWN3D!'">click here</em>' + ' snippetn</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…
  6. 6. G O O D B Y E N G - B I N D - H T M L - U N S A F E
  7. 7. 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 htmln' + ' <em onmouseover="this.textContent='PWN3D!'">click here</em>' + ' snippetn</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>
  8. 8. 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)
  9. 9. 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…
  10. 10. 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>
  11. 11. $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)
  12. 12. 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()
  13. 13. S O W H Y WA 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
  14. 14. 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…
  15. 15. 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.URL URLs 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]
  16. 16. 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); });
  17. 17. 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
  18. 18. 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 (misko@hevery.com) * based on: HTML Parser By John Resig (ejohn.org) * Original code by Erik Arvidsson, Mozilla Public License */
  19. 19. 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

×