material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

[CSP] Issue with inline-style and Content Security Policy

Open lwilkins opened this issue 5 years ago • 26 comments

According to the documentation, to support the CSP header, a nonce needs to be added to the style-src directive (https://mui.com/material-ui/guides/content-security-policy/). However, a number of Material-UI components make use of inline style attributes (e.g. Tabs - https://github.com/mui/material-ui/blob/5c96f3cad765c259d029321a8f7d2f57c9bcc36b/packages/mui-material/src/Tabs/Tabs.js#L768-L773). These require the 'unsafe-inline' source (or a hash for each style although this isn't practical). The 'unsafe-inline' source is ignored if a hash or nonce source is set, thus necessitating the removal of the nonce.

So generally for Material-UI as I see it, I think one of two things are needed:

  1. Update the CSP documentation for a setup to allow inline style attribute setting (not a great CSP, but would make Material-UIs stance clear on styling then).
  2. Set a standard of no inline style attribute setting and we fix them all as bugs.

What do you think? I did an issue search and found this (https://github.com/mui-org/material-ui/issues/13364) suggesting that Material-UI as a whole allows inline style attributes and thus are happy with necessitating a non strict CSP setting. Is this still the case and we're happy with what this means for CSP?

Related:

  • https://github.com/radix-ui/primitives/issues/2057

lwilkins avatar Mar 02 '20 17:03 lwilkins

Generally I think we shouldn't use inline styles to begin with since they make customizing harder. So ideally we wouldn't use inline styles at all.

In the meantime we should add this notice to the docs.

eps1lon avatar Mar 02 '20 18:03 eps1lon

This concern seems important for the use of the components in high demanding environments, e.g; #13364 coming from SnapChat Inc.? However, from our issue history, most developers seem to loosen the CSP for it.

We do have a couple of components that rely on inline style:

  • SpeedDial
  • Skeleton
  • AvatarGroup
  • Autocomplete
  • TextareaAutosize
  • Tabs
  • SwipeableDrawer
  • Slider
  • Modal
  • LinearProgress
  • CircularProgress
  • GridList
  • Collapse
  • Fade
  • Grow
  • Zoom
  • CardMedia
  • ButtonBase

Wow, ok, actually, it's much more than I thought.

I think that it would be interesting to explore:

  • What's the alternative? (cost)
  • How much better is it without inline-style? Who actually needs it?

oliviertassinari avatar Mar 02 '20 20:03 oliviertassinari

Thanks for the input @eps1lon and @oliviertassinari . I'll loosen the CSP in my application for now, but exploring the removal of all inline style attributes would be great and would be something I'd support.

lwilkins avatar Mar 03 '20 10:03 lwilkins

Just coming here as I was surprised to find out I still had CSP errors after following the docs: https://mui.com/material-ui/guides/content-security-policy/

It looks like the docs were never updated as suggested, so I opened a PR. Hopefully, someone has an updated list of the "non-csp" components #21479.

razor-x avatar Jun 17 '20 03:06 razor-x

https://developers.google.com/web/fundamentals/security/csp/#inline_code_is_considered_harmful makes a case in favor of removing all inline style.

oliviertassinari avatar Jun 18 '20 09:06 oliviertassinari

@razor-x It seems that we have lost your contribution (#21479) along the way in v5: https://mui.com/guides/content-security-policy/. There are no more mentions of inline-styles and what needs to be done to handle them. We will also likely need to update the guide for emotion, our new default style engine for v5.

oliviertassinari avatar Dec 23 '20 12:12 oliviertassinari

@oliviertassinari just happen to be checking in on the progress towards Material UI v5 and remembered about this update. Ideally in v5 CSP would be fully supported by all the hard work done on switching everything to emotion 🤞🏻 .

That said, I do believe my update to the docs in https://github.com/mui-org/material-ui/pull/21479 should have been pushed to the v4 docs and not bumped to v5. After all, my original goal with that update was to save time for any CSP users on v4 by letting them know of this edge case. I'm sure there will still be quite some time before all v4 users are moved to v5, so I'd like to get that back in if possible. Best.

razor-x avatar Jun 29 '21 16:06 razor-x

Hi @oliviertassinari! Any news on the issue?

tasola avatar Oct 26 '21 07:10 tasola

Multiline TextFields are still broken in Material UI v5.4.1 with a nonce-based CSP, unfortunately. Any plans on fixing this?

ghost avatar Feb 15 '22 19:02 ghost

we have the same issue on cssinjs here. we have any updates here? 👍

tiennguyen1293 avatar Mar 01 '22 09:03 tiennguyen1293

Bigger picture 2¢: Why wasn't CSS-in-CSS the default option? If CSS-in-JS wasn't a trend, we wouldn't see these issues popping up that require non-trivial workarounds. From my fresh-to-MUI viewpoint, this feels like it's bordering on bug not feature territory.

toastal avatar Mar 01 '22 09:03 toastal

@toastal The issue we track here is the use of inline-style. For example, if we consider:

https://github.com/mui/material-ui/blob/3aa59189e566baa225a89f962214441f02787abc/packages/mui-base/src/TextareaAutosize/TextareaAutosize.js#L171-L177

How do we replace this to be compatible without style-src: 'unsafe-inline' https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src#unsafe_inline_styles?

CSS-in-CSS vs. CSS-in-JS is not really a variable on the problem faced, at best CSS-in-JS could be a solution because it allows dynamic values.

There are some discussions about this root issue in the standard working group, e.g. https://github.com/w3c/webappsec-csp/issues/45 but I couldn't find really anything concrete to help.

The option to use CSS-in-JS in the above example would mean that we should add to the unstyled component a dependency on a styling library, e.g. emotion, IMHO, it doesn't fly.

https://github.com/rrweb-io/rrweb/issues/816#issuecomment-1051065366 is encouraging. It suggests that approved JS scripts can use the CSSOM API so some of this list https://github.com/mui/material-ui/issues/19938#issuecomment-593618428 could be solved. If anybody has the bandwidth, feel free to dive deeper.

I suspect that there are components that we won't be able to migrate, hence it would be great to document this problem in https://mui.com/guides/content-security-policy/.

oliviertassinari avatar Mar 26 '22 21:03 oliviertassinari

How do we replace this to be compatible without style-src: 'unsafe-inline' https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src#unsafe_inline_styles?

CSS-in-CSS vs. CSS-in-JS is not really a variable on the problem faced, at best CSS-in-JS could be a solution because it allows dynamic values.

I wonder if this library can take a similar approach to what Next.JS does to solve this issue: hoist the dynamic CSS into a <style> block with a nonce that the CSP can reference: https://github.com/vercel/next.js/issues/18557 (implemented in https://github.com/vercel/next.js/pull/19150). Then, none of the CSS is actually rendered inline, but the developer experience is pretty similar (vs. static CSS-in-CSS).

Note that this approach shifts some security responsibility to the library that's inserting the dynamic CSS into the nonce-having <style> block. If the library allows untrusted user input to make it into the <style> block, then it's vulnerable to the same issues as style-src 'unsafe-inline'.

It's probably going to require a fair amount of work to migrate all of the current inline styles into hoisted dynamic <style> styles, but I'd strongly suggest moving in that direction since attacker-manipulated inline styles can lead to exfiltration of private user data: https://scarybeastsecurity.blogspot.com/2009/12/generic-cross-browser-cross-domain.html. Having a CSP without style-src 'unsafe-inline' significantly reduces the portion of a site's code that can insert an attacker's malicious CSS into the page, since only the code that directly maintains the <style> blocks needs to be trusted. Without CSP, or with style-src 'unsafe-line', essentially any buggy code on the page could provide an attack vector for inserting untrusted CSS into the page.

ramosbugs avatar Mar 26 '22 22:03 ramosbugs

[TextareaAutosize.js] example; “dynamic values”

This could easily be a utility class that is pushed/popped instead of needing to edit the CSS “dynamically” (e.g. .MUITextarea.shouldHideOverflow { overflow: hidden }) (or if CSS variables where on the allowlist for CSP). JavaScript is allowed to dynamically add/remove items from the classList without a CSP concern so why is this not the first solution option? I don’t see what CSS-in-JS gives you other than slower processing speeds and extra complexity.

<style> block with a nonce

This is in the category of “non-trivial workarounds”… Needing to add complicated steps to the build pipeline is adding more complexity to the issue. This is a band-aid for what seems like a poor architecture decision. Users should not be required to whip out heavy guns like webpack to calculate nonces when there are simpler alternatives (see above).


I’m open to being wrong, but I am really not ‘getting it’ when it comes to CSS-in-JS. Currently in my multiple consulting gigs I’m suggesting clients migrate away from anything using CSS-in-JS now and has anecdotally appeared to have simplified the setup and tooling after a little CSS guidance.

toastal avatar Mar 27 '22 02:03 toastal

Any updates on this? Is there any date when mui won't have inline-styles or put them into

zhdanouskikh avatar Jun 21 '22 10:06 zhdanouskikh

also interested in knowing if there are any updates to this. is there a list of components that have/have not been migrated?

indefinitelee avatar Aug 11 '22 16:08 indefinitelee

Any updates on this? Is there any date when mui won't have inline-styles or put them into

2 months since my comment and noone replied. Nice job 👍

zhdanouskikh avatar Aug 11 '22 17:08 zhdanouskikh

@oliviertassinari Not sure if the issue is related to my setup or not, but for some components that rely on inline style such as textField, the style attributes are missing on SSR. I'm facing a style mismatch between SSR and CSR after hydration.

Before hydration: Screenshot 2022-11-29 104007

After hydration: Screenshot 2022-11-29 104132

Maybe they are being added at a later stage after rendering is done?

iMrDJAi avatar Nov 29 '22 09:11 iMrDJAi

I think some dynamic styling is unavoidable, in the case of images. When you want to provide a pleasant loading experience you need to tell the browser what the aspect ratio is, and if you have a lot of images that means a lot of possible aspect ratios.

Currently I pass the ratio as a CSS variable in a style attribute on the wrapping component. How to solve this, especially when you have a SPA that needs to dynamically insert images?

wmertens avatar Feb 04 '23 06:02 wmertens

Any updates on this? We are also blocked from using material UI for our project because of strict CSP policies mainly unsafe-inline.

RanVaknin avatar Aug 04 '23 21:08 RanVaknin

I created a reproduction with TextareaAutosize: https://codesandbox.io/p/sandbox/throbbing-browser-rkms3j?file=/next.config.js:33,18.

Screenshot 2023-08-21 at 13 14 54 Screenshot 2023-08-21 at 13 15 01

As for solutions,

  1. CSS variables
import * as React from "react";

export default function UnstyledTextareaIntroduction() {
  return (
    <div
      style={{
        "--foo": "bar",
      }}
    >
      Hello
    </div>
  );
}

doesn't work, not unless https://github.com/w3c/webappsec-csp/issues/174 makes progress.

  1. ref.current.style access. This seems to work, it's explained in https://github.com/w3c/webappsec-csp/issues/174#issuecomment-830733922. It was applied in https://github.com/carbon-design-system/carbon/pull/12784.
  2. When SSR is required, <style> with nonce attributes, e.g. https://github.com/shuding/react-wrap-balancer/blob/eb363827ef806119caaa5ffd3e4135bde1f43811/src/index.tsx#L113

oliviertassinari avatar Aug 20 '23 22:08 oliviertassinari

The documentation should be more clear. In my case Accordion was also doing inline style breaking the CSP.

My workaround is to use style-src-attr 'unsafe-inline' instead of doing it on style-src which would break in case of already using a nonce for third-party files. It's not perfect, but the attack vector seems minimal to me like that.

sneko avatar Mar 11 '24 17:03 sneko

not sure why this is an issue when emotion is available. Isn't the OP code trivially

 css={css`
   overflow: ${scrollerStyle.overflow};
   ${!visibleScrollbar
     ? (vertical
       ? `margin-${isRtl ? "left" : "right"}`
       : 'margin-bottom') + `: ${-scrollerStyle.scrollbarWidth};`
     : "" }
 `} 

?

frattaro avatar Mar 11 '24 18:03 frattaro

Can we please remove inline styles entirely? What prevents us from using CSS modules or plain old classes? That would simplify CSPs and allow Web applications to be less lenient with security. If we add a nonce to style-src, the unsafe-inline keyword doesn't appear to work, so this is currently a blocker for us.

yesudeep avatar Jul 17 '24 20:07 yesudeep

Agree, inline styles break SSR as well.

iMrDJAi avatar Jul 17 '24 20:07 iMrDJAi

We've dropped MUI in favor of https://github.com/rmwc/rmwc

yesudeep avatar Aug 22 '24 03:08 yesudeep

We've dropped MUI in favor of https://github.com/rmwc/rmwc

Does rmwc allow to pass CSP without 'unsafe-inline'?

saislam10 avatar Sep 30 '24 15:09 saislam10

@saislam10 we extract all static inline styles known at build time. There doesn't appear to be a runtime component so far, so I'd be inclined to say yes.

yesudeep avatar Oct 02 '24 22:10 yesudeep

I am building a React SPA with Vite using MUI v6, emotion, and styled components. I then set a strict CSP policy for the style source. The app won't render since MUI components are using inline styles. I could not find a viable solution to use CSP with the MUI components. Can you please at least update the MUI CSP docs with relevant information for SPAs for the most popular build tool atm. The CRA is not being maintained anymore.

pritesha avatar Mar 06 '25 00:03 pritesha