aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChirayu Krishnappa2013-11-12 15:32:52 -0800
committerIgor Minar2013-11-21 23:15:15 -0800
commit0421cb4200e672818ed10996e92311404c150c3a (patch)
tree384b9bc6236a62a0b9a01fa406b1cdb83d7e9aad
parent6f1050df4fa885bd59ce85adbef7350ea93911a3 (diff)
downloadangular.js-0421cb4200e672818ed10996e92311404c150c3a.tar.bz2
fix($compile): secure form[action] & iframe[srcdoc]
Require bindings to form[action] to be $sce.RESOURCE_URL and bindings to iframe[srcdoc] to be $sce.HTML Closes #4927 Closes #4933
-rw-r--r--src/ng/compile.js9
-rwxr-xr-xtest/ng/compileSpec.js70
2 files changed, 77 insertions, 2 deletions
diff --git a/src/ng/compile.js b/src/ng/compile.js
index d977f173..4eb12019 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -1780,10 +1780,15 @@ function $CompileProvider($provide) {
function getTrustedContext(node, attrNormalizedName) {
+ if (attrNormalizedName == "srcdoc") {
+ return $sce.HTML;
+ }
+ var tag = nodeName_(node);
// maction[xlink:href] can source SVG. It's not limited to <maction>.
if (attrNormalizedName == "xlinkHref" ||
- (nodeName_(node) != "IMG" && (attrNormalizedName == "src" ||
- attrNormalizedName == "ngSrc"))) {
+ (tag == "FORM" && attrNormalizedName == "action") ||
+ (tag != "IMG" && (attrNormalizedName == "src" ||
+ attrNormalizedName == "ngSrc"))) {
return $sce.RESOURCE_URL;
}
}
diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js
index 5b6e1ada..99be8afc 100755
--- a/test/ng/compileSpec.js
+++ b/test/ng/compileSpec.js
@@ -4232,6 +4232,76 @@ describe('$compile', function() {
}));
});
+ describe('form[action]', function() {
+ it('should pass through action attribute for the same domain', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
+ $rootScope.testUrl = "different_page";
+ $rootScope.$apply();
+ expect(element.attr('action')).toEqual('different_page');
+ }));
+
+ it('should clear out action attribute for a different domain', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
+ $rootScope.testUrl = "http://a.different.domain.example.com";
+ expect(function() { $rootScope.$apply() }).toThrowMinErr(
+ "$interpolate", "interr", "Can't interpolate: {{testUrl}}\nError: [$sce:insecurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "http://a.different.domain.example.com");
+ }));
+
+ it('should clear out JS action attribute', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
+ $rootScope.testUrl = "javascript:alert(1);";
+ expect(function() { $rootScope.$apply() }).toThrowMinErr(
+ "$interpolate", "interr", "Can't interpolate: {{testUrl}}\nError: [$sce:insecurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: " +
+ "javascript:alert(1);");
+ }));
+
+ it('should clear out non-resource_url action attribute', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
+ $rootScope.testUrl = $sce.trustAsUrl("javascript:doTrustedStuff()");
+ expect($rootScope.$apply).toThrowMinErr(
+ "$interpolate", "interr", "Can't interpolate: {{testUrl}}\nError: [$sce:insecurl] Blocked " +
+ "loading resource from url not allowed by $sceDelegate policy. URL: javascript:doTrustedStuff()");
+ }));
+
+ it('should pass through $sce.trustAs() values in action attribute', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
+ $rootScope.testUrl = $sce.trustAsResourceUrl("javascript:doTrustedStuff()");
+ $rootScope.$apply();
+
+ expect(element.attr('action')).toEqual('javascript:doTrustedStuff()');
+ }));
+ });
+
+ if (!msie || msie >= 11) {
+ describe('iframe[srcdoc]', function() {
+ it('should NOT set iframe contents for untrusted values', inject(function($compile, $rootScope, $sce) {
+ element = $compile('<iframe srcdoc="{{html}}"></iframe>')($rootScope);
+ $rootScope.html = '<div onclick="">hello</div>';
+ expect(function() { $rootScope.$digest(); }).toThrowMinErr('$interpolate', 'interr', new RegExp(
+ /Can't interpolate: {{html}}\n/.source +
+ /[^[]*\[\$sce:unsafe\] Attempting to use an unsafe value in a safe context./.source));
+ }));
+
+ it('should NOT set html for wrongly typed values', inject(function($rootScope, $compile, $sce) {
+ element = $compile('<iframe srcdoc="{{html}}"></iframe>')($rootScope);
+ $rootScope.html = $sce.trustAsCss('<div onclick="">hello</div>');
+ expect(function() { $rootScope.$digest(); }).toThrowMinErr('$interpolate', 'interr', new RegExp(
+ /Can't interpolate: {{html}}\n/.source +
+ /[^[]*\[\$sce:unsafe\] Attempting to use an unsafe value in a safe context./.source));
+ }));
+
+ it('should set html for trusted values', inject(function($rootScope, $compile, $sce) {
+ element = $compile('<iframe srcdoc="{{html}}"></iframe>')($rootScope);
+ $rootScope.html = $sce.trustAsHtml('<div onclick="">hello</div>');
+ $rootScope.$digest();
+ expect(angular.lowercase(element[0].srcdoc)).toEqual('<div onclick="">hello</div>');
+ }));
+ });
+ }
+
describe('ngAttr* attribute binding', function() {
it('should bind after digest but not before', inject(function($compile, $rootScope) {