This repository has been archived by the owner on Apr 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix($compile): secure form[action] & iframe[srcdoc] #4933
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4016,6 +4016,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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the error message should read ".... in sensitive context" not "safe context" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Acknowledged. Changing this requires also changing about 10 other places (in sce.js and sceSpecs.js) so let's do that in a separate commit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok |
||
})); | ||
|
||
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) { | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unless we are sure that we have an exhaustive list of sensitive html attributes I wouldn't even bother with this fix. the purpose of this check is to guide developers not to use data-binding with onclick and similar events and not to prevent attackers that can exploit server-side security holes from using data-binding as an attack vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are actually two separate checks we already do:
onclick
,formaction
, andfriends. These attribs are always Javascript and we
have better alternatives. This fix is not about
that.
$sce.getTrustedResourceUrl()
foriframe[src]
, etc. This PR is about this point.[code.google.com/p/mustache-security][] has nice things to
say about the security of 1.2. There are only 2 points
called out – of which only the first is significant and this
PR addresses it.
I agree with you that this isn't exhaustive.
That said, we aren't missing much and an affected app would
have to actively be using an attribute we've
missed. Merging this PR is keeping in the spirit of what
we're already doing to
*[src]
andxlink-href
– otherwisewe should remove those checks and just leave it to the
developer.