feat(core): create a Trusted Types policy for bypass conversions (#39218)
When an application uses a custom sanitizer or one of the bypassSecurityTrust functions, Angular has no way of knowing whether they are implemented in a secure way. (It doesn't even know if they're introduced by the application or by a shady third-party dependency.) Thus using Angular's main Trusted Types policy to bless values coming from these two sources would undermine the security that Trusted Types brings. Instead, introduce a Trusted Types policy called angular#unsafe-bypass specifically for blessing values from these sources. This allows an application to enforce Trusted Types even if their application uses a custom sanitizer or the bypassSecurityTrust functions, knowing that compromises to either of these two sources may lead to arbitrary script execution. In the future Angular will provide a way to implement custom sanitizers in a manner that makes better use of Trusted Types. PR Close #39218
This commit is contained in:
parent
9ec2bad4dc
commit
49197d12a0
|
@ -0,0 +1,89 @@
|
||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google LLC All Rights Reserved.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview
|
||||||
|
* A module to facilitate use of a Trusted Types policy internally within
|
||||||
|
* Angular specifically for bypassSecurityTrust* and custom sanitizers. It
|
||||||
|
* lazily constructs the Trusted Types policy, providing helper utilities for
|
||||||
|
* promoting strings to Trusted Types. When Trusted Types are not available,
|
||||||
|
* strings are used as a fallback.
|
||||||
|
* @security All use of this module is security-sensitive and should go through
|
||||||
|
* security review.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {global} from '../global';
|
||||||
|
import {TrustedHTML, TrustedScript, TrustedScriptURL, TrustedTypePolicy, TrustedTypePolicyFactory} from './trusted_type_defs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Trusted Types policy, or null if Trusted Types are not
|
||||||
|
* enabled/supported, or undefined if the policy has not been created yet.
|
||||||
|
*/
|
||||||
|
let policy: TrustedTypePolicy|null|undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Trusted Types policy, or null if Trusted Types are not
|
||||||
|
* enabled/supported. The first call to this function will create the policy.
|
||||||
|
*/
|
||||||
|
function getPolicy(): TrustedTypePolicy|null {
|
||||||
|
if (policy === undefined) {
|
||||||
|
policy = null;
|
||||||
|
if (global.trustedTypes) {
|
||||||
|
try {
|
||||||
|
policy = (global.trustedTypes as TrustedTypePolicyFactory)
|
||||||
|
.createPolicy('angular#unsafe-bypass', {
|
||||||
|
createHTML: (s: string) => s,
|
||||||
|
createScript: (s: string) => s,
|
||||||
|
createScriptURL: (s: string) => s,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// trustedTypes.createPolicy throws if called with a name that is
|
||||||
|
// already registered, even in report-only mode. Until the API changes,
|
||||||
|
// catch the error not to break the applications functionally. In such
|
||||||
|
// cases, the code will fall back to using strings.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafely promote a string to a TrustedHTML, falling back to strings when
|
||||||
|
* Trusted Types are not available.
|
||||||
|
* @security This is a security-sensitive function; any use of this function
|
||||||
|
* must go through security review. In particular, it must be assured that it
|
||||||
|
* is only passed strings that come directly from custom sanitizers or the
|
||||||
|
* bypassSecurityTrust* functions.
|
||||||
|
*/
|
||||||
|
export function trustedHTMLFromStringBypass(html: string): TrustedHTML|string {
|
||||||
|
return getPolicy()?.createHTML(html) || html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafely promote a string to a TrustedScript, falling back to strings when
|
||||||
|
* Trusted Types are not available.
|
||||||
|
* @security This is a security-sensitive function; any use of this function
|
||||||
|
* must go through security review. In particular, it must be assured that it
|
||||||
|
* is only passed strings that come directly from custom sanitizers or the
|
||||||
|
* bypassSecurityTrust* functions.
|
||||||
|
*/
|
||||||
|
export function trustedScriptFromStringBypass(script: string): TrustedScript|string {
|
||||||
|
return getPolicy()?.createScript(script) || script;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafely promote a string to a TrustedScriptURL, falling back to strings
|
||||||
|
* when Trusted Types are not available.
|
||||||
|
* @security This is a security-sensitive function; any use of this function
|
||||||
|
* must go through security review. In particular, it must be assured that it
|
||||||
|
* is only passed strings that come directly from custom sanitizers or the
|
||||||
|
* bypassSecurityTrust* functions.
|
||||||
|
*/
|
||||||
|
export function trustedScriptURLFromStringBypass(url: string): TrustedScriptURL|string {
|
||||||
|
return getPolicy()?.createScriptURL(url) || url;
|
||||||
|
}
|
Loading…
Reference in New Issue