Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(core): hardening attribute and property binding rules for <iframe…
…> elements (#47964) This commit updates the logic related to the attribute and property binding rules for <iframe> elements. There is a set of <iframe> attributes that may affect the behavior of an iframe and this change enforces that these attributes are only applied as static attributes, making sure that they are taken into account while creating an <iframe>. If Angular detects that some of the security-sensitive attributes are applied as an attribute or property binding, it throws an error message, which contains the name of an attribute that is causing the problem and the name of a Component where an iframe is located. BREAKING CHANGE: Existing iframe usages may have security-sensitive attributes applied as an attribute or property binding in a template or via host bindings in a directive. Such usages would require an update to ensure compliance with the new stricter rules around iframe bindings. PR Close #47964
- Loading branch information
1 parent
54d0981
commit 28f289b
Showing
14 changed files
with
999 additions
and
6 deletions.
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
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
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
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 |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* @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 | ||
*/ | ||
|
||
import {IFRAME_SECURITY_SENSITIVE_ATTRS, SECURITY_SCHEMA} from '../src/schema/dom_security_schema'; | ||
|
||
|
||
describe('security-related tests', () => { | ||
it('should have no overlap between `IFRAME_SECURITY_SENSITIVE_ATTRS` and `SECURITY_SCHEMA`', | ||
() => { | ||
// The `IFRAME_SECURITY_SENSITIVE_ATTRS` and `SECURITY_SCHEMA` tokens configure sanitization | ||
// and validation rules and used to pick the right sanitizer function. | ||
// This test verifies that there is no overlap between two sets of rules to flag | ||
// a situation when 2 sanitizer functions may be needed at the same time (in which | ||
// case, compiler logic should be extended to support that). | ||
const schema = new Set(); | ||
Object.keys(SECURITY_SCHEMA()).forEach((key: string) => schema.add(key.toLowerCase())); | ||
let hasOverlap = false; | ||
IFRAME_SECURITY_SENSITIVE_ATTRS.forEach(attr => { | ||
if (schema.has('*|' + attr) || schema.has('iframe|' + attr)) { | ||
hasOverlap = true; | ||
} | ||
}); | ||
expect(hasOverlap).toBeFalse(); | ||
}); | ||
}); |
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
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
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 |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* @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 | ||
*/ | ||
|
||
import {RuntimeError, RuntimeErrorCode} from '../errors'; | ||
import {getTemplateLocationDetails} from '../render3/instructions/element_validation'; | ||
import {TNodeType} from '../render3/interfaces/node'; | ||
import {RComment, RElement} from '../render3/interfaces/renderer_dom'; | ||
import {RENDERER} from '../render3/interfaces/view'; | ||
import {nativeRemoveNode} from '../render3/node_manipulation'; | ||
import {getLView, getSelectedTNode} from '../render3/state'; | ||
import {getNativeByTNode} from '../render3/util/view_utils'; | ||
import {trustedHTMLFromString} from '../util/security/trusted_types'; | ||
|
||
|
||
/** | ||
* Validation function invoked at runtime for each binding that might potentially | ||
* represent a security-sensitive attribute of an <iframe>. | ||
* See `IFRAME_SECURITY_SENSITIVE_ATTRS` in the | ||
* `packages/compiler/src/schema/dom_security_schema.ts` script for the full list | ||
* of such attributes. | ||
* | ||
* @codeGenApi | ||
*/ | ||
export function ɵɵvalidateIframeAttribute(attrValue: any, tagName: string, attrName: string) { | ||
const lView = getLView(); | ||
const tNode = getSelectedTNode()!; | ||
const element = getNativeByTNode(tNode, lView) as RElement | RComment; | ||
|
||
// Restrict any dynamic bindings of security-sensitive attributes/properties | ||
// on an <iframe> for security reasons. | ||
if (tNode.type === TNodeType.Element && tagName.toLowerCase() === 'iframe') { | ||
const iframe = element as HTMLIFrameElement; | ||
|
||
// Unset previously applied `src` and `srcdoc` if we come across a situation when | ||
// a security-sensitive attribute is set later via an attribute/property binding. | ||
iframe.src = ''; | ||
iframe.srcdoc = trustedHTMLFromString('') as unknown as string; | ||
|
||
// Also remove the <iframe> from the document. | ||
nativeRemoveNode(lView[RENDERER], iframe); | ||
|
||
const errorMessage = ngDevMode && | ||
`Angular has detected that the \`${attrName}\` was applied ` + | ||
`as a binding to an <iframe>${getTemplateLocationDetails(lView)}. ` + | ||
`For security reasons, the \`${attrName}\` can be set on an <iframe> ` + | ||
`as a static attribute only. \n` + | ||
`To fix this, switch the \`${attrName}\` binding to a static attribute ` + | ||
`in a template or in host bindings section.`; | ||
throw new RuntimeError(RuntimeErrorCode.UNSAFE_IFRAME_ATTRS, errorMessage); | ||
} | ||
return attrValue; | ||
} |
Oops, something went wrong.