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

Inline <style> elements violates style-src Content Security Policy #6361

Closed
jelbourn opened this issue Jan 8, 2016 · 40 comments
Closed

Inline <style> elements violates style-src Content Security Policy #6361

jelbourn opened this issue Jan 8, 2016 · 40 comments
Assignees
Labels
area: core Issues related to the framework runtime area: security Issues related to built-in security features, such as HTML sanitation core: stylesheets cross-cutting: CSP feature Issue that requests a new feature freq3: high security Issues that generally impact framework or application security state: has PR
Milestone

Comments

@jelbourn
Copy link
Member

jelbourn commented Jan 8, 2016

See https://developer.mozilla.org/en-US/docs/Web/Security/CSP/CSP_policy_directives#style-src

The framework should support users that want to build their apps for CSP. In this case, the style-src directive would be in violation by Angular 2's use of inline <style> elements for things like CSS encapsulation.

I was curious if Angular 1 supported CSP, and it seems that Angular 1 indeed generates a stylesheet (build/angular-csp.css) that users can consume for CSP mode.

cc @tbosch @matsko

@tpetersheim

This comment has been minimized.

@fredericoramos78

This comment has been minimized.

@xnnkmd
Copy link

xnnkmd commented Oct 23, 2017

@IgorMinar Can this be fixed so we can write secure Angular apps ?

@skatterwe

This comment has been minimized.

@ngbot ngbot bot added this to the Backlog milestone Jan 23, 2018
@ghost

This comment has been minimized.

@eranation

This comment has been minimized.

@alexleen
Copy link

alexleen commented Nov 15, 2018

+1

As a workaround, we had to move all of our component level styles to a global style sheet. This meant creating src/styles.css, copying over all of our component styles, and adding this file to the .angular-cli.json styles array. All *.component.css files were then removed.

See component styles and global styles for more information.

Note: changing the view encapsulation did not seem to work (as some suggested).

@epeschier
Copy link

We did the same as @alexleen.
But when you do a production build, angular will still leave an empty <style></style> tag in the head of the HTML document, resulting in a style-src csp error in the browser console. The app is running but can this be removed somehow?

@redevill
Copy link

redevill commented Feb 21, 2019

Is this due to the shared_styles_host.ts file line 47?

   this._styleNodes.add(host.appendChild(styleEl));

This is the spot my CSP is identifying, and was wondering if this is the same issue?

@theRaffe

This comment has been minimized.

@jnmalapati
Copy link

any update or workarounds for this issue ?

+1

As a workaround, we had to move all of our component level styles to a global style sheet. This meant creating src/styles.css, copying over all of our component styles, and adding this file to the .angular-cli.json styles array. All *.component.css files were then removed.

See component styles and global styles for more information.

Note: changing the view encapsulation did not seem to work (as some suggested).

This doesn't seem to be work. Angular still adds the global styles as inline to the index.html file, not as a separate file.

@kgergooo
Copy link

@redevill That this._styleNodes.add(host.appendChild(styleEl)); can be because of an angular dependency. I also moved the component level styles into a global style but still getting the same csp inline style error, so I created a non minified angular build and I debugged the build. I get the csp errors because of the angular material npm package.

@Splaktar
Copy link
Member

That this._styleNodes.add(host.appendChild(styleEl)); can be because of an angular dependency. I also moved the component level styles into a global style but still getting the same csp inline style error, so I created a non minified angular build and I debugged the build. I get the csp errors because of the angular material npm package.

@kgergooo Material has a couple of related, closed issues (angular/components#12139, angular/components#17783) but nothing open for CSP atm other then docs (angular/components#12795). If you can create a reproduction of the problem, please open a new issue at https://github.com/angular/components/issues/new/choose.

@schivmeister
Copy link

schivmeister commented Oct 12, 2020

Hijacking this issue as some discussion on this._styleNodes.add(host.appendChild(styleEl)); has already taken place...

We use Angular 9 for a true single-page application, meaning -- in addition to it being as good as a fully static website -- the server plays absolutely no part in templating whatsoever. With a "traditional" CSP configuration (which can be quite restrictive if we are specific about paths), we are still getting these violations from the main-es2015.* file (from different lines), which are beyond our control:

this._styleNodes.add(host.appendChild(styleEl));
...
(/** @type {?} */ (_document.head)).appendChild(styleEl);
...
el.setAttribute(name, value);

Each of these I suspect belong to webpack, flex-layout and/or ivy (could be material too but I didn't want to bother our front-end dev yet), and understand to be integral parts of Angular. This requires us to use unsafe-inline for the style-src directive, which is not acceptable as we intend to get security clearances at financial institutions.

The nonce-based "strict" mode is not a configuration that we can use, which is made clear by this FAQ. Using hashes is not a nice option either, since these hashes change on every build, even without changes in the code base!

When we decided to use Angular some years ago, we decided to trust the community and company behind it, but we ended up being quite surprised that such basic and well-documented security practices are not yet covered, given that it has been more than 4-5 years since widespread adoption by browsers.

Or, maybe Angular is ahead of the times...

@SymbioticKilla

This comment has been minimized.

@Rugshtyne
Copy link

As I've expressed in this Angular Material issue, this is even affecting Angular Material and changes would be greatly appreciated. It would be great to have as a solution a possibility to add CSP nonces to the injected style tags.

We have used 'unsafe-hashes' for some of the styles attributes but now, according to the government of Netherlands, which we have to comply to, these should be removed.

If some other workaround is possible or a minor fix in a code would do, it would be great to get that information.

@Rugshtyne
Copy link

[...] because the risk associated with this policy is very low.

What's the reasoning behind this?

Personally I would prefer Angular not to require inline styles. They have their own attack vectors[1][2] and these could be relevant depending on an app's context.

Sorry for double post but I think that this post was overlooked. We would like to hear some reasoning from Google why they think the risk is low. Especially having in mind that we have to deal with Netherlands' government and their security concerns.

@heinerlamprecht
Copy link

heinerlamprecht commented Aug 12, 2022

I discussed this with the security team at google, and they are not concerned about Angular requiring default-src self; style-src unsafe-inline; as the default policy, because the risk associated with this policy is very low.

We are updating the Angular docs to reflect this: #43553

Does anyone have a concern about this?

@IgorMinar Do you have any official statement / source from the security team? The problem is, that many authorities at least in Europe nowadays require very strict CSP settings. "unsafe-inline" is simply not allowed and it is nearly impossible to discuss this topic with those kind of customers. As a result, Angular can not be used in these environments.

@flash-me
Copy link
Contributor

@Rugshtyne

As I've expressed in this Angular Material issue, this is even affecting Angular Material and changes would be greatly appreciated. It would be great to have as a solution a possibility to add CSP nonces to the injected style tags.

We have used 'unsafe-hashes' for some of the styles attributes but now, according to the government of Netherlands, which we have to comply to, these should be removed.

If some other workaround is possible or a minor fix in a code would do, it would be great to get that information.

Why on earth noone hit on the idea to provide their own DomSharedStylesHost ?
Especially if you have requirements like this @heinerlamprecht

@IgorMinar Do you have any official statement / source from the security team? The problem is, that many authorities at least in Europe nowadays require very strict CSP settings. "unsafe-inline" is simply not allowed and it is nearly impossible to discuss this topic with those kind of customers. As a result, Angular can not be used in these environments.

I mean @redevill even pointed to the right direction: #6361 (comment)

Step 1

Copy Contents of https://github.com/angular/angular/blob/main/packages/platform-browser/src/dom/shared_styles_host.ts

Step 2

Adjust the Service to fit your needs.
image

Step 3

Provide your own Implementation

import { NgModule } from '@angular/core';
import {BrowserModule, ɵDomSharedStylesHost} from '@angular/platform-browser';
import { AppComponent } from './app.component';
import {CustomDomSharedStylesHostService} from "./custom-dom-shared-styles-host.service";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [
    {provide: ɵDomSharedStylesHost, useClass: CustomDomSharedStylesHostService}  // PROVIDE OWN IMPLEMENTATION
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 4

Profit lol
image

Further improvements:

  • Provide the required nonce value via environment files or sth like that before building the application OR
  • even load the value from a backend before bootstrapping the application so you will have a different nonce each time the application loads.

Code

CustomDomSharedStylesHostService

Some Code

import {Inject, Injectable} from "@angular/core";
import {DOCUMENT, ɵgetDOM as getDOM} from "@angular/common";

/**
* Contents copied from
* https://github.com/angular/angular/blob/main/packages/platform-browser/src/dom/shared_styles_host.ts
* Provides custom DomSharedStylesHostService with own logic
*/

const SOME_RANDOM_NONCE: string = "blabla";

@Injectable()
export class SharedStylesHost {
  /** @internal */
  protected _stylesSet = new Set<string>();

  addStyles(styles: string[]): void {
  	const additions = new Set<string>();
  	styles.forEach(style => {
  		if (!this._stylesSet.has(style)) {
  			this._stylesSet.add(style);
  			additions.add(style);
  		}
  	});
  	this.onStylesAdded(additions);
  }

  onStylesAdded(additions: Set<string>): void {}

  getAllStyles(): string[] {
  	return Array.from(this._stylesSet);
  }
}

@Injectable()
export class CustomDomSharedStylesHostService extends SharedStylesHost {
  private _hostNodes = new Map<Node, Node[]>();

  constructor(@Inject(DOCUMENT) private _doc: any) {
  	super();
  	this._hostNodes.set(_doc.head, []);
  }

  private _addStylesToHost(styles: Set<string>, host: Node, styleNodes: Node[]): void {
  	styles.forEach((style: string) => {
  		const styleEl: HTMLStyleElement = this._doc.createElement('style');
  		styleEl.textContent = style;
  		// CUSTOM LOGIC
  		styleEl.setAttribute('nonce', SOME_RANDOM_NONCE)
  		console.log("Oh my gosh, 6 year old isse still open");
  		// CUSTOM LOGIC END
  		styleNodes.push(host.appendChild(styleEl));
  	});
  }

  addHost(hostNode: Node): void {
  	const styleNodes: Node[] = [];
  	this._addStylesToHost(this._stylesSet, hostNode, styleNodes);
  	this._hostNodes.set(hostNode, styleNodes);
  }

  removeHost(hostNode: Node): void {
  	const styleNodes = this._hostNodes.get(hostNode);
  	if (styleNodes) {
  		styleNodes.forEach(removeStyle);
  	}
  	this._hostNodes.delete(hostNode);
  }

  override onStylesAdded(additions: Set<string>): void {
  	this._hostNodes.forEach((styleNodes, hostNode) => {
  		this._addStylesToHost(additions, hostNode, styleNodes);
  	});
  }

  ngOnDestroy(): void {
  	this._hostNodes.forEach(styleNodes => styleNodes.forEach(removeStyle));
  }
}

function removeStyle(styleNode: Node): void {
  getDOM().remove(styleNode);
}

cheers
flash ⚡

@Rugshtyne
Copy link

Rugshtyne commented Sep 22, 2022

@flash-me
We have this workaround since day 1, see comment angular/components#24633 (comment) .

What is wrong with this is that it's

... a hacky and not future proof way to tackle the issue, especially given the fact that Angular themselves have made some workarounds where they just inject style node into the DOM, bypassing the mentioned host.

@flash-me
Copy link
Contributor

@flash-me We have this workaround since day 1, see comment angular/components#24633 (comment) .

What is wrong with this is that it's

... a hacky and not future proof way to tackle the issue, especially given the fact that Angular themselves have made some workarounds where they just inject style node into the DOM, bypassing the mentioned host.

Thx for the info! Was not aware of what

cheers
flash ⚡

@samudra77
Copy link

Apart from the solution being hacky, it doesn't fix the issues in angular sister projects like material and flex-layout. We are stuck with this at this point.

@amanplans
Copy link

I was able to implement the workaround from @ferdiesletering.

But I encountered an error from the layout.mjs file. The error states:

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' 'nonce-tHgVnqAPEWmMlyKzB3ekFsMX' fonts.googleapis.com". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.

As you see, there is a nonce in the CSP header, so why is layout.mjs still throwing this error on line 83:
document.head.appendChild(mediaQueryStyleNode);?

@Asphiii
Copy link

Asphiii commented Feb 27, 2023

I was able to implement the workaround from @ferdiesletering.

But I encountered an error from the layout.mjs file. The error states:

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' 'nonce-tHgVnqAPEWmMlyKzB3ekFsMX' fonts.googleapis.com". Either the 'unsafe-inline' keyword, a hash ('sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU='), or a nonce ('nonce-...') is required to enable inline execution.

As you see, there is a nonce in the CSP header, so why is layout.mjs still throwing this error on line 83: document.head.appendChild(mediaQueryStyleNode);?

same issue for me

@crisbeto crisbeto assigned crisbeto and unassigned JoostK Mar 8, 2023
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 16, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

These changes address adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 16, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

This PR addresses adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 16, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

This PR addresses adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 16, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

This PR addresses adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 16, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

This PR addresses adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 17, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

This PR addresses adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
crisbeto added a commit to crisbeto/angular that referenced this issue Mar 17, 2023
Angular uses inline styles to insert the styles associated with a component. This violates the strict styles [Content Security Policy](https://web.dev/strict-csp/) which doesn't allow inline styles by default. One way to allow the styles to be applied is to set a `nonce` attribute on them, but because the code for inserting the stylesheets is deep inside the framework, users weren't able to provide it without accessing private APIs.

These changes add a new `CSP_NONCE` injection token that will allow users to provide a nonce, if their app is using CSP. If the token isn't provided, the framework will look for an `ngCspNonce` attribute on the app's root node instead. The latter approach is provided as a convenience for apps that render the `index.html` through a server, e.g. `<app ngCspNonce="{% randomNonceAddedByTheServer %}"></app>`.

This PR addresses adding the nonce to framework-generated styles. There will be follow-up PRs that add support for it in critical CSS tags in the CLI, and in Angular Material.

Fixes angular#6361.
@grafanauser
Copy link

@flash-me solution makes only sense when you do what he says in the last point: load a different nounce everytime the application loads. otherwise it is not safe at all.

@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 May 7, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: core Issues related to the framework runtime area: security Issues related to built-in security features, such as HTML sanitation core: stylesheets cross-cutting: CSP feature Issue that requests a new feature freq3: high security Issues that generally impact framework or application security state: has PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.