JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.62k stars 4.12k forks source link

[V2] Request/Bug: Needs CSP Considerations #2917

Open icd2k3 opened 6 years ago

icd2k3 commented 6 years ago

We use a pretty strict CSP which doesn't allow unsafe-inline for style-src. Therefore, when we try to use react-select we get the following errors (and an un-styled react-select component):

Refused to apply inline style because it violates the following Content Security Policy directive: "style-src 'self' Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.

Unfortunately this is blocking us from using this wonderful component!

I noticed this old issue: https://github.com/JedWatson/react-select/issues/2030, but the props autosize and inputProps have been removed in v2.

EDIT: It looks maybe the best way to add support for this is by using create-emotion which includes the ability to use a single <style> tag with a nonce attribute?

kristiehowboutdat commented 6 years ago

Is the original issue #2030 the only CSP issue now? This is also a blocker for using react-select. Going to try and get v1 to work now as a workaround

icd2k3 commented 6 years ago

@kristiehowboutdat this is also related https://github.com/JedWatson/react-select/issues/2167 but unfortunately is also referencing v1...

I had a brief look at the v2 source code and it looks as though it will need an update in order to work with strict CSPs. Might have some free time to dig into it a bit more in the near future unless someone beats me to it! 🤞

kristiehowboutdat commented 6 years ago

Took a little time yesterday to try and circumvent. Solved the inputProps issue (getting injectStyles={false} onto the AutosizeInput via "replacing" the component, with no visual change.

/* Some sample code to demonstrate */

// @flow
import * as React from 'react';
import Select, { components } from 'react-select';

const Input = props => {
  return <components.Input {...props} injectStyles={false} />;
};

class MySelect extends React.Component<Props> {
  render() {
    const { onChange } = this.props;

    return (
      <Select
        ref={ref => (this.select = ref)}
        autoFocus
        components={{ Input }}
        onChange={onChange}
      />
    );
  }
}

export default MySelect;

Verifying with a Jest Snapshot....(a lot of stuff deleted for simplicity)

                    <Input
                      aria-autocomplete="list"
                      autoCapitalize="none"
                      autoComplete="off"
                      autoCorrect="off"
                      cx={[Function]}
                      getStyles={[Function]}
                      id="org-select-input"
                      injectStyles={false}
                      innerRef={[Function]}
                      isDisabled={false}
                      isHidden={false}
                      onBlur={[Function]}
                      onChange={[Function]}
                      onFocus={[Function]}
                      spellCheck="false"
                      tabIndex="0"
                      type="text"
                      value=""
                    >
                      <div
                        className="css-rsyb7x"
                      >
                        <AutosizeInput
                          aria-autocomplete="list"
                          autoCapitalize="none"
                          autoComplete="off"
                          autoCorrect="off"
                          className=""
                          disabled={false}
                          id="org-select-input"
/* It's provided here */
                          injectStyles={false}
                          inputRef={[Function]}
                          inputStyle={
                            Object {
                              "background": 0,
                              "border": 0,
                              "color": "inherit",
                              "fontSize": "inherit",
                              "opacity": 1,
                              "outline": 0,
                              "padding": 0,
                            }
                          }
                          minWidth={1}
                          onBlur={[Function]}
                          onChange={[Function]}
                          onFocus={[Function]}
                          spellCheck="false"
                          tabIndex="0"
                          type="text"
                          value=""
                        >
                          /* Removing for brevity */
                        </AutosizeInput>
                      </div>
                    </Input>

However, that was not enough as you mentioned (my csp prevents unsafe-inline as well. There's still a <style data-emotion></style> tag injected in the <head>).

icd2k3 commented 6 years ago

Yep, emotion does have support for CSP nonces, but react-select will have to surface that option to be passed to emotion.

zwiepsel commented 6 years ago

I also have the same problem that its blocked by the CSP policy. @icd2k3 did you found a way to allow it now? cause it is indeed a wonderfull component but we cant use it either

edmorley commented 5 years ago

Hi! Thank you for looking into this - however I don't think the solution in #3260 helps in the majority of cases?

The CSS spec says (source):

For each request, the server generates a unique value at random, and includes it in the Content-Security-Policy header

Which is emphasised in Google's CSP Guide:

Remember that nonces must be regenerated for every page request and they must be unguessable.

ie: Adding CSS nonce support to react-select:

Please can this issue be reopened?

gwyneplaine commented 5 years ago

@icd2k3 and anyone else relying on nonce support in selects. I'm re-opening this issue as I've just released 2.3.0 that reverts the following PR #3260. Please see #3346 for the reasoning behind this reversion.

If nonce support is critical for your app, please pin react-select at 2.2.0 until further notice. Nonce support will be reintroduced in 3.0.0 under the following PR #3321 , on release I'll ping this issue once more.

gwyneplaine commented 5 years ago

@edmorley, how the nonce is provided to both the react environment and the header of the statically served asset seems like a separate concern to providing that value to react-select (and thus emotion). So I'm as of yet unsure as to how #3260 directly conflicts with the use-case you've provided.

But if it is indeed not the correct solution what would be the alternative, I want to make sure that our provision of nonce to emotion through react-select makes sense, and works for everyone.

edmorley commented 5 years ago

Hi! My concerns were:

  1. That unless the messaging was clear, it would be easy for users to think #3260 was the correct solution even when using static hard coded CSP headers (and not realise doing so would be a security issue) ie: footgun potential.
  2. That by closing this issue it might suggest it was resolved, when really what some of us would like is for emotion support to be optional, and to have a way to disable inline styles entirely.
javidang commented 4 years ago

in the end what was resolution for this? did you find any workaround ?

richmeij commented 4 years ago

Hi, Im using Creatable in a project, and its not clear to me how to set/pass a nonce to react-select. Is there any documentation regarding this? Or maybe its possible to disable injecting CSS?

cjadhav commented 2 years ago

Hi Any updates on this..? Not able to use any styles in React-Select... Using React 17 and React-select v5.

TIA

zedtux commented 2 years ago

I'm also looking for updates on this issue aged of 3 years and a half.

Rall3n commented 2 years ago

A solution on how to provide a nonce to react-select has already been mentioned in a newer issue https://github.com/JedWatson/react-select/issues/4631#issuecomment-999483078.

To provide a nonce you must use CacheProvider and createCache from emotion (the CSS-in-JS library used). It is recommended to place the CacheProvider at the root of your application, to cover every instance of the Select component available.

import { createCache } from '@emotion/cache';
import { CacheProvider } from '@emotion/react';

const cache = createCache({
  key: 'my-cache-key',
  nonce: THE_NONCE    // <----
});

const App = () => {
  // ...
  return (<CacheProvider value={cache}>
    {/* ... */}
  </CacheProvider>);
}
AlexMachin1997 commented 2 years ago

@Rall3n I've just tired that and I'm still getting the csp error as seen below

image

Rall3n commented 2 years ago

@AlexMachin1997

The error message tells you exactly what you have to do. Naturally setting the nonce for the cache object is not enough. You also have to adjust your CSP to include the nonce:

// HTTP-Header: "Content-Security-Policy: style-src 'nonce-...'"
<meta http-equiv="Content-Security-Policy" content="style-src 'nonce-...'" />
AlexMachin1997 commented 2 years ago

@Rall3n In the end we just ended up modifying the rules to allow inline "styles" in our security headers.

shehi commented 6 months ago

React 18 has server-components now. With them, nonces become a viable solution. Is there any plans for this?

Better yet, why not support Module-based SCSS?! I would be happy to have SCSS files as part of the library - then I would include them wherever necessary. React-Select styles shouldn't be that big... @JedWatson , thoughts?