This repository was 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.4k
fix($sanitize): Use same whitelist mechanism as $compile does. #5137
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 hidden or 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 hidden or 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 hidden or 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 hidden or 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 |
---|---|---|
@@ -0,0 +1,74 @@ | ||
'use strict'; | ||
|
||
/** | ||
* @description | ||
* Private service to sanitize uris for links and images. Used by $compile and $sanitize. | ||
*/ | ||
function $$SanitizeUriProvider() { | ||
var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/, | ||
imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//; | ||
|
||
/** | ||
* @description | ||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe | ||
* urls during a[href] sanitization. | ||
* | ||
* The sanitization is a security measure aimed at prevent XSS attacks via html links. | ||
* | ||
* Any url about to be assigned to a[href] via data-binding is first normalized and turned into | ||
* an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist` | ||
* regular expression. If a match is found, the original url is written into the dom. Otherwise, | ||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. | ||
* | ||
* @param {RegExp=} regexp New regexp to whitelist urls with. | ||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for | ||
* chaining otherwise. | ||
*/ | ||
this.aHrefSanitizationWhitelist = function(regexp) { | ||
if (isDefined(regexp)) { | ||
aHrefSanitizationWhitelist = regexp; | ||
return this; | ||
} | ||
return aHrefSanitizationWhitelist; | ||
}; | ||
|
||
|
||
/** | ||
* @description | ||
* Retrieves or overrides the default regular expression that is used for whitelisting of safe | ||
* urls during img[src] sanitization. | ||
* | ||
* The sanitization is a security measure aimed at prevent XSS attacks via html links. | ||
* | ||
* Any url about to be assigned to img[src] via data-binding is first normalized and turned into | ||
* an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` | ||
* regular expression. If a match is found, the original url is written into the dom. Otherwise, | ||
* the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM. | ||
* | ||
* @param {RegExp=} regexp New regexp to whitelist urls with. | ||
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for | ||
* chaining otherwise. | ||
*/ | ||
this.imgSrcSanitizationWhitelist = function(regexp) { | ||
if (isDefined(regexp)) { | ||
imgSrcSanitizationWhitelist = regexp; | ||
return this; | ||
} | ||
return imgSrcSanitizationWhitelist; | ||
}; | ||
|
||
this.$get = function() { | ||
return function sanitizeUri(uri, isImage) { | ||
var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; | ||
var normalizedVal; | ||
// NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case. | ||
if (!msie || msie >= 8 ) { | ||
normalizedVal = urlResolve(uri).href; | ||
if (normalizedVal !== '' && !normalizedVal.match(regex)) { | ||
return 'unsafe:'+normalizedVal; | ||
} | ||
} | ||
return uri; | ||
}; | ||
}; | ||
} | ||
This file contains hidden or 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 hidden or 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 |
---|---|---|
|
@@ -46,6 +46,8 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); | |
* it into the returned string, however, since our parser is more strict than a typical browser | ||
* parser, it's possible that some obscure input, which would be recognized as valid HTML by a | ||
* browser, won't make it through the sanitizer. | ||
* The whitelist is configured using the functions `aHrefSanitizationWhitelist` and | ||
* `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. | ||
* | ||
* @param {string} html Html input. | ||
* @returns {string} Sanitized html. | ||
|
@@ -128,11 +130,24 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); | |
</doc:scenario> | ||
</doc:example> | ||
*/ | ||
var $sanitize = function(html) { | ||
function $SanitizeProvider() { | ||
this.$get = ['$$sanitizeUri', function($$sanitizeUri) { | ||
return function(html) { | ||
var buf = []; | ||
htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { | ||
return !/^unsafe/.test($$sanitizeUri(uri, isImage)); | ||
})); | ||
return buf.join(''); | ||
}; | ||
}]; | ||
} | ||
|
||
function sanitizeText(chars) { | ||
var buf = []; | ||
htmlParser(html, htmlSanitizeWriter(buf)); | ||
return buf.join(''); | ||
}; | ||
var writer = htmlSanitizeWriter(buf, angular.noop); | ||
writer.chars(chars); | ||
return buf.join(''); | ||
} | ||
|
||
|
||
// Regular Expressions for parsing tags and attributes | ||
|
@@ -145,7 +160,6 @@ var START_TAG_REGEXP = | |
COMMENT_REGEXP = /<!--(.*?)-->/g, | ||
DOCTYPE_REGEXP = /<!DOCTYPE([^>]*?)>/i, | ||
CDATA_REGEXP = /<!\[CDATA\[(.*?)]]>/g, | ||
URI_REGEXP = /^((ftp|https?):\/\/|mailto:|tel:|#)/i, | ||
// Match everything outside of normal chars and " (quote character) | ||
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; | ||
|
||
|
@@ -353,8 +367,18 @@ function htmlParser( html, handler ) { | |
*/ | ||
var hiddenPre=document.createElement("pre"); | ||
function decodeEntities(value) { | ||
hiddenPre.innerHTML=value.replace(/</g,"<"); | ||
return hiddenPre.innerText || hiddenPre.textContent || ''; | ||
if (!value) { | ||
return ''; | ||
} | ||
// Note: IE8 does not preserve spaces at the start/end of innerHTML | ||
var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; | ||
var parts = spaceRe.exec(value); | ||
parts[0] = ''; | ||
if (parts[2]) { | ||
hiddenPre.innerHTML=parts[2].replace(/</g,"<"); | ||
parts[2] = hiddenPre.innerText || hiddenPre.textContent; | ||
} | ||
return parts.join(''); | ||
} | ||
|
||
/** | ||
|
@@ -384,7 +408,7 @@ function encodeEntities(value) { | |
* comment: function(text) {} | ||
* } | ||
*/ | ||
function htmlSanitizeWriter(buf){ | ||
function htmlSanitizeWriter(buf, uriValidator){ | ||
var ignore = false; | ||
var out = angular.bind(buf, buf.push); | ||
return { | ||
|
@@ -398,7 +422,9 @@ function htmlSanitizeWriter(buf){ | |
out(tag); | ||
angular.forEach(attrs, function(value, key){ | ||
var lkey=angular.lowercase(key); | ||
if (validAttrs[lkey]===true && (uriAttrs[lkey]!==true || value.match(URI_REGEXP))) { | ||
var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); | ||
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.
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. or would that be a breaking change? 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. That would be a breaking change, as it was supported before. 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 |
||
if (validAttrs[lkey] === true && | ||
(uriAttrs[lkey] !== true || uriValidator(value, isImage))) { | ||
out(' '); | ||
out(key); | ||
out('="'); | ||
|
@@ -430,4 +456,4 @@ function htmlSanitizeWriter(buf){ | |
|
||
|
||
// define ngSanitize module and register $sanitize service | ||
angular.module('ngSanitize', []).value('$sanitize', $sanitize); | ||
angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider); |
Oops, something went wrong.
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.
missing blank line at the end of the file