Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(material/icon): make icon-registry compatible with Trusted Types #23140

Merged
merged 1 commit into from
Sep 3, 2021

Conversation

bjarkler
Copy link
Contributor

@bjarkler bjarkler commented Jul 9, 2021

When Angular Material is used in an environment that enforces Trusted Types, the icon registry raises a Trusted Types violation due to its use of element.innerHTML when initializing SVG icons.

To make the icon registry compatible with Trusted Types, SvgIconConfig.svgText is changed to a TrustedHTML, and its users updated to either produce TrustedHTML (making sure to only do so in cases where its security can be readily assessed) or pass such values along.

To facilitate this, add a module that provides a Trusted Types policy, angular#components, for use internally by Angular Material. The policy is created lazily and stored in a module-local variable. This is the same as the approach taken by Angular proper in
https://github.com/angular/angular/blob/master/packages/core/src/util/security/trusted_types.ts

Helper functions for unsafely converting a string to a TrustedHTML is also introduced, with documentation to make it clear that its use requires a security review. When Trusted Types are not available, the helper function falls back to returning strings, facilitating backwards-compatibility with environments that do not support Trusted Types.

@bjarkler bjarkler requested a review from jelbourn as a code owner July 9, 2021 11:50
@google-cla google-cla bot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Jul 9, 2021
@bjarkler bjarkler requested a review from IgorMinar July 9, 2021 11:50
@bjarkler bjarkler force-pushed the icon-tt branch 2 times, most recently from 9419464 to 35cfa62 Compare July 9, 2021 12:15
@bjarkler bjarkler requested a review from a team as a code owner July 9, 2021 12:15
* that will be interpreted as HTML by a browser, e.g. when assigning to
* element.innerHTML.
*/
export function trustedHTMLFromString(html: string): TrustedHTML {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small comment: Should this be named so that its unsafeness is clear from the function name?

(Sorry, I'm not the most familiar with Angular naming conventions, so please excuse me if that's not feasible here.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this with the Angular team while preparing angular/angular#39207. The issue is that the code minifier that they use doesn't change function names, so a longer more clear name would likely impact code size. This was the name that we landed on as a compromise.

@josephperrott josephperrott removed the request for review from a team July 9, 2021 16:30
if (typeof window !== 'undefined') {
const ttWindow = window as unknown as {trustedTypes?: TrustedTypePolicyFactory};
if (ttWindow.trustedTypes !== undefined) {
policy = ttWindow.trustedTypes.createPolicy('material#icon', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that it would be better to create a single policy for all of @angular/material (and even @angular/cdk), but that would require us to figure out how to securely share it between all of the entry points (e.g. @angular/material/icon).

I don't believe that we have such sharing mechanism today. We do have a concept of private exports in other packages, but this only obfuscates the export name with a hard to type prefix — ɵ (example) which is not good enough for a trusted type policy.

I wonder if there is another way to do this.

The main concern with entry-point level policy names is that there could be too many of them added over time, which would make it a nightmare to manage the policy names within the server configuration.

Copy link
Contributor

@IgorMinar IgorMinar Jul 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aside: the name of the policy could also be changed to be more consistent with our existing angular policies, for example angular#material or angular#components.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, the name of the policy should include "angular" in the name.

As for sharing, I don't know if doing something cross-library possible? I don't know the trusted types system super well, but it seems like the policy object needs to be inaccessible to userspace, yes? If that's the case, there's no mechanism such that another material entry-point could access it while userspace couldn't.

That said, we don't use innerHTML anywhere else in material or cdk- the SVG handling here for icons is special since SVGs are assets that also need to be inlined into the DOM. I would like to move this svg handling code into the cdk in the future, but we can cross that bridge when we get to it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jelbourn what policy name would you prefer? angular#material, angular#cdk, or angular#components?

+1 for keeping the code here for now, as long as we don't foresee a need to do other security-sensitive DOM operations elsewhere in material or cdk.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the name to angular#components to allow us to use it both for material and cdk in the future. Would be happy to change this if you have other preferences.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm!

When Angular Material is used in an environment that enforces Trusted
Types, the icon registry raises a Trusted Types violation due to its use
of element.innerHTML when initializing SVG icons.

To make the icon registry compatible with Trusted Types,
SvgIconConfig.svgText is changed to a TrustedHTML, and its users updated
to either produce TrustedHTML (making sure to only do so in cases where
its security can be readily assessed) or pass such values along.

To facilitate this, add a module that provides a Trusted Types policy,
'angular#components'. The policy is created lazily and stored in a
module-local variable. This is the same as the approach taken by Angular
proper in
https://github.com/angular/angular/blob/master/packages/core/src/util/security/trusted_types.ts
Copy link
Member

@jelbourn jelbourn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jelbourn jelbourn added target: minor This PR is targeted for the next minor release G This is is related to a Google internal issue P2 The issue is important to a large percentage of users, with a workaround labels Jul 20, 2021
@jelbourn jelbourn added the action: merge The PR is ready for merge by the caretaker label Aug 16, 2021
@bjarkler
Copy link
Contributor Author

bjarkler commented Sep 2, 2021

global presubmit looks good, and that ngcc_compatibility failure looks like a flake. Can we merge this? :)

@zarend zarend merged commit 881edec into angular:master Sep 3, 2021
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Oct 4, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement G This is is related to a Google internal issue P2 The issue is important to a large percentage of users, with a workaround target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants