aboutsummaryrefslogtreecommitdiffstats
path: root/src/ng/compile.js
diff options
context:
space:
mode:
authorIgor Minar2013-02-19 09:55:05 -0800
committerIgor Minar2013-02-20 00:40:51 -0800
commita8cc4497063118c766bdfa9464c9cbfc59413a81 (patch)
treee2940be3b1ebc026a1b6a124bf53de8839fd6e60 /src/ng/compile.js
parent2aa212b19c71df82287b4b074da3ab14cbf37348 (diff)
downloadangular.js-a8cc4497063118c766bdfa9464c9cbfc59413a81.tar.bz2
fix($compile): sanitize values bound to a[href]
Diffstat (limited to 'src/ng/compile.js')
-rw-r--r--src/ng/compile.js58
1 files changed, 52 insertions, 6 deletions
diff --git a/src/ng/compile.js b/src/ng/compile.js
index 2ed34f73..84a9c3ca 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -155,7 +155,8 @@ function $CompileProvider($provide) {
Suffix = 'Directive',
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
- MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ';
+ MULTI_ROOT_TEMPLATE_ERROR = 'Template must have exactly one root element. was: ',
+ urlSanitizationWhitelist = /^\s*(https?|ftp|mailto):/;
/**
@@ -209,11 +210,41 @@ function $CompileProvider($provide) {
};
+ /**
+ * @ngdoc function
+ * @name ng.$compileProvider#urlSanitizationWhitelist
+ * @methodOf ng.$compileProvider
+ * @function
+ *
+ * @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 `urlSanitizationWhitelist` 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 it is 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.urlSanitizationWhitelist = function(regexp) {
+ if (isDefined(regexp)) {
+ urlSanitizationWhitelist = regexp;
+ return this;
+ }
+ return urlSanitizationWhitelist;
+ };
+
+
this.$get = [
'$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
- '$controller', '$rootScope',
+ '$controller', '$rootScope', '$document',
function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
- $controller, $rootScope) {
+ $controller, $rootScope, $document) {
var Attributes = function(element, attr) {
this.$$element = element;
@@ -235,7 +266,8 @@ function $CompileProvider($provide) {
*/
$set: function(key, value, writeAttr, attrName) {
var booleanKey = getBooleanAttrName(this.$$element[0], key),
- $$observers = this.$$observers;
+ $$observers = this.$$observers,
+ normalizedVal;
if (booleanKey) {
this.$$element.prop(key, value);
@@ -254,6 +286,19 @@ function $CompileProvider($provide) {
}
}
+
+ // sanitize a[href] values
+ if (nodeName_(this.$$element[0]) === 'A' && key === 'href') {
+ urlSanitizationNode.setAttribute('href', value);
+
+ // href property always returns normalized absolute url, so we can match against that
+ normalizedVal = urlSanitizationNode.href;
+ if (!normalizedVal.match(urlSanitizationWhitelist)) {
+ this[key] = value = 'unsafe:' + normalizedVal;
+ }
+ }
+
+
if (writeAttr !== false) {
if (value === null || value === undefined) {
this.$$element.removeAttr(attrName);
@@ -297,7 +342,8 @@ function $CompileProvider($provide) {
}
};
- var startSymbol = $interpolate.startSymbol(),
+ var urlSanitizationNode = $document[0].createElement('a'),
+ startSymbol = $interpolate.startSymbol(),
endSymbol = $interpolate.endSymbol(),
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
? identity
@@ -1025,10 +1071,10 @@ function $CompileProvider($provide) {
function addAttrInterpolateDirective(node, directives, value, name) {
var interpolateFn = $interpolate(value, true);
-
// no interpolation found -> ignore
if (!interpolateFn) return;
+
directives.push({
priority: 100,
compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {