refactor: disable sanitization for [style] and [style.prop] bindings (#35621)
This patch is the first of many commits to disable sanitization for [stlye.prop] and [style] bindings in Angular. Historically, style-based sanitization has only been required for old IE browsers (IE6 and IE7). Since Angular does not support these old browsers at all, there is no reason for the framework to support style-based sanitization. PR Close #35621
This commit is contained in:

committed by
Alex Rickabaugh

parent
3c6c00d1d4
commit
420b9be1c1
@ -15,7 +15,7 @@ import {allowSanitizationBypassAndThrow, BypassType, unwrapSafeValue} from './by
|
||||
import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer';
|
||||
import {Sanitizer} from './sanitizer';
|
||||
import {SecurityContext} from './security';
|
||||
import {_sanitizeStyle, StyleSanitizeFn, StyleSanitizeMode} from './style_sanitizer';
|
||||
import {StyleSanitizeFn, StyleSanitizeMode} from './style_sanitizer';
|
||||
import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer';
|
||||
|
||||
|
||||
@ -50,14 +50,10 @@ export function ɵɵsanitizeHtml(unsafeHtml: any): string {
|
||||
* A `style` sanitizer which converts untrusted `style` **string** into trusted string by removing
|
||||
* dangerous content.
|
||||
*
|
||||
* This method parses the `style` and locates potentially dangerous content (such as urls and
|
||||
* javascript) and removes it.
|
||||
*
|
||||
* It is possible to mark a string as trusted by calling {@link bypassSanitizationTrustStyle}.
|
||||
*
|
||||
* @param unsafeStyle untrusted `style`, typically from the user.
|
||||
* @returns `style` string which is safe to bind to the `style` properties, because all of the
|
||||
* dangerous javascript and urls have been removed.
|
||||
* @returns `style` string which is safe to bind to the `style` properties.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
@ -69,7 +65,7 @@ export function ɵɵsanitizeStyle(unsafeStyle: any): string {
|
||||
if (allowSanitizationBypassAndThrow(unsafeStyle, BypassType.Style)) {
|
||||
return unwrapSafeValue(unsafeStyle);
|
||||
}
|
||||
return _sanitizeStyle(renderStringify(unsafeStyle));
|
||||
return renderStringify(unsafeStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,8 +177,14 @@ export function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl: any, tag: string, prop:
|
||||
}
|
||||
|
||||
/**
|
||||
* The default style sanitizer will handle sanitization for style properties by
|
||||
* sanitizing any CSS property that can include a `url` value (usually image-based properties)
|
||||
* The default style sanitizer will handle sanitization for style properties.
|
||||
*
|
||||
* Style sanitization is no longer apart of Angular because modern browsers no
|
||||
* longer support javascript expressions. Therefore, the reason why this API
|
||||
* exists is exclusively for unwrapping any style value expressions that were
|
||||
* marked as `SafeValue` values.
|
||||
*
|
||||
* This API will be removed in a future release of Angular.
|
||||
*
|
||||
* @publicApi
|
||||
*/
|
||||
|
@ -5,104 +5,22 @@
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {isDevMode} from '../util/is_dev_mode';
|
||||
import {SafeValue} from './bypass';
|
||||
import {_sanitizeUrl} from './url_sanitizer';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for safe style values.
|
||||
/*
|
||||
* ========== WARNING ==========
|
||||
*
|
||||
* Quotes (" and ') are allowed, but a check must be done elsewhere to ensure they're balanced.
|
||||
* Style sanitization in Angular (for `[style.prop]` and `[style]` bindings)
|
||||
* is no longer required and has been removed. The reason why this feature
|
||||
* has been removed is because style-based sanitization is no longer
|
||||
* required with modern browsers.
|
||||
*
|
||||
* ',' allows multiple values to be assigned to the same property (e.g. background-attachment or
|
||||
* font-family) and hence could allow multiple values to get injected, but that should pose no risk
|
||||
* of XSS.
|
||||
* The contents of this file are still in flux. Various APIs and symbols will
|
||||
* be removed in a future version of Angular. Please hold off from modifying this
|
||||
* file for the time being.
|
||||
*
|
||||
* The function expression checks only for XSS safety, not for CSS validity.
|
||||
*
|
||||
* This regular expression was taken from the Closure sanitization library, and augmented for
|
||||
* transformation values.
|
||||
* =============================
|
||||
*/
|
||||
const VALUES = '[-,."\'%_!# a-zA-Z0-9]+';
|
||||
const TRANSFORMATION_FNS = '(?:matrix|translate|scale|rotate|skew|perspective)(?:X|Y|Z|3d)?';
|
||||
const COLOR_FNS = '(?:rgb|hsl)a?';
|
||||
const GRADIENTS = '(?:repeating-)?(?:linear|radial)-gradient';
|
||||
const CSS3_FNS = '(?:attr|calc|var)';
|
||||
const FN_ARGS = '\\([-0-9.%, #a-zA-Z]+\\)';
|
||||
const SAFE_STYLE_VALUE = new RegExp(
|
||||
`^(${VALUES}|` +
|
||||
`(?:${TRANSFORMATION_FNS}|${COLOR_FNS}|${GRADIENTS}|${CSS3_FNS})` +
|
||||
`${FN_ARGS})$`,
|
||||
'g');
|
||||
|
||||
/**
|
||||
* Matches a `url(...)` value with an arbitrary argument as long as it does
|
||||
* not contain parentheses.
|
||||
*
|
||||
* The URL value still needs to be sanitized separately.
|
||||
*
|
||||
* `url(...)` values are a very common use case, e.g. for `background-image`. With carefully crafted
|
||||
* CSS style rules, it is possible to construct an information leak with `url` values in CSS, e.g.
|
||||
* by observing whether scroll bars are displayed, or character ranges used by a font face
|
||||
* definition.
|
||||
*
|
||||
* Angular only allows binding CSS values (as opposed to entire CSS rules), so it is unlikely that
|
||||
* binding a URL value without further cooperation from the page will cause an information leak, and
|
||||
* if so, it is just a leak, not a full blown XSS vulnerability.
|
||||
*
|
||||
* Given the common use case, low likelihood of attack vector, and low impact of an attack, this
|
||||
* code is permissive and allows URLs that sanitize otherwise.
|
||||
*/
|
||||
const URL_RE = /^url\(([^)]+)\)$/;
|
||||
|
||||
/**
|
||||
* Checks that quotes (" and ') are properly balanced inside a string. Assumes
|
||||
* that neither escape (\) nor any other character that could result in
|
||||
* breaking out of a string parsing context are allowed;
|
||||
* see http://www.w3.org/TR/css3-syntax/#string-token-diagram.
|
||||
*
|
||||
* This code was taken from the Closure sanitization library.
|
||||
*/
|
||||
function hasBalancedQuotes(value: string) {
|
||||
let outsideSingle = true;
|
||||
let outsideDouble = true;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
const c = value.charAt(i);
|
||||
if (c === '\'' && outsideDouble) {
|
||||
outsideSingle = !outsideSingle;
|
||||
} else if (c === '"' && outsideSingle) {
|
||||
outsideDouble = !outsideDouble;
|
||||
}
|
||||
}
|
||||
return outsideSingle && outsideDouble;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the given untrusted CSS style property value (i.e. not an entire object, just a single
|
||||
* value) and returns a value that is safe to use in a browser environment.
|
||||
*/
|
||||
export function _sanitizeStyle(value: string): string {
|
||||
value = String(value).trim(); // Make sure it's actually a string.
|
||||
if (!value) return '';
|
||||
|
||||
// Single url(...) values are supported, but only for URLs that sanitize cleanly. See above for
|
||||
// reasoning behind this.
|
||||
const urlMatch = value.match(URL_RE);
|
||||
if ((urlMatch && _sanitizeUrl(urlMatch[1]) === urlMatch[1]) ||
|
||||
value.match(SAFE_STYLE_VALUE) && hasBalancedQuotes(value)) {
|
||||
return value; // Safe style values.
|
||||
}
|
||||
|
||||
if (isDevMode()) {
|
||||
console.warn(
|
||||
`WARNING: sanitizing unsafe style value ${value} (see http://g.co/ng/security#xss).`);
|
||||
}
|
||||
|
||||
return 'unsafe';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A series of flags to instruct a style sanitizer to either validate
|
||||
|
Reference in New Issue
Block a user