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/
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. 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. – N O O N E E V E R
“We can trust our users and the input they provide.”
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. G O O D B Y E
N G - B I N D - H T M L - U N S A F E
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. 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. 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. 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>
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
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. 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. 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. 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. 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