Amplify-js: browserOrNode() breaks pages with strict Content-Security-Policy headers

Created on 16 Jan 2020  Ā·  6Comments  Ā·  Source: aws-amplify/amplify-js

Describe the bug
The JS.browserOrNode() function uses eval-like expressions that prevent amplify-js from running when a strict Content-Security-Policy is in place. The eval-like expressions I'm talking about are new Function("..."), which are not allowed in a Content-Security-Policy, that doesn't allow eval().

This leads to the following error message in the browser (in this case Firefox):

Content Security Policy: The page’s settings blocked the loading of a resource at eval (ā€œdefault-srcā€). vendor.js

This prevents us from using any of the functionality provided by amplify-js. I believe the issue was introduced with commit 52bd2877bee66b934885e6726b68c8a926c28c3d, which changed the functionality in browserOrNode() to use new Function().

To Reproduce

  1. Have a page with a Content-Security-Policy that defines default-src 'self'; (script-src 'self'; should also work), see Sample Code for the one we are using.
  2. Include any amplify-js package that uses JS.browserOrNode() (in our case @aws-amplify/auth).
  3. See error in the browser's console (and possibly on the page), the package will not be working as expected

Expected behavior
amplify-js (or rather browserOrNode()) should not break any Content-Security-Policy that forbids eval()

Screenshots
Error in Firefox console:
image

Error in Google Chrome console:
image


Environment

  System:
    OS: Linux 5.3 Ubuntu 19.10 (Eoan Ermine)
    CPU: (4) x64 Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
    Memory: 141.61 MB / 7.64 GB
    Container: Yes
    Shell: 5.0.3 - /bin/bash
  Binaries:
    Node: 12.14.1 - /usr/bin/node
    Yarn: 1.21.1 - /usr/bin/yarn
    npm: 6.13.4 - /usr/bin/npm
  Browsers:
    Chrome: 79.0.3945.117
    Firefox: 72.0.1
  npmPackages:
    @aws-amplify/auth: ^2.1.3 => 2.1.3 
    @babel/core: ^7.8.3 => 7.8.3 
    @babel/preset-env: ^7.8.3 => 7.8.3 
    @babel/preset-react: ^7.8.3 => 7.8.3 
    @testing-library/jest-dom: ^4.2.4 => 4.2.4 
    @testing-library/react: ^9.4.0 => 9.4.0 
    @testing-library/react-hooks: ^3.2.1 => 3.2.1 
    @types/jest: ^24.9.0 => 24.9.0 
    @types/react: ^16.9.17 => 16.9.17 
    babel-eslint: ^10.0.3 => 10.0.3 
    babel-loader: ^8.0.6 => 8.0.6 
    copy-webpack-plugin: ^5.1.1 => 5.1.1 
    core-js: ^3.6.4 => 3.6.4 
    dotenv: ^8.2.0 => 8.2.0 
    eslint: ^6.8.0 => 6.8.0 
    eslint-config-airbnb: ^18.0.1 => 18.0.1 
    eslint-config-jameda: ^1.6.4 => 1.6.4 
    eslint-config-prettier: ^6.9.0 => 6.9.0 
    eslint-import-resolver-webpack: ^0.12.1 => 0.12.1 
    eslint-plugin-import: ^2.20.0 => 2.20.0 
    eslint-plugin-jest: ^23.6.0 => 23.6.0 
    eslint-plugin-jsx-a11y: ^6.2.3 => 6.2.3 
    eslint-plugin-react: ^7.18.0 => 7.18.0 
    eslint-plugin-react-hooks: ^2.3.0 => 2.3.0 
    file-loader: ^5.0.2 => 5.0.2 
    history: ^4.10.1 => 4.10.1 
    html-webpack-plugin: ^3.2.0 => 3.2.0 
    husky: ^4.0.10 => 4.0.10 
    jest: ^24.9.0 => 24.9.0 
    jest-junit: ^10.0.0 => 10.0.0 
    jest-styled-components: ^7.0.0 => 7.0.0 
    lint-staged: ^9.5.0 => 9.5.0 
    prettier: ^1.19.1 => 1.19.1 
    prettier-eslint: ^9.0.1 => 9.0.1 
    prettier-eslint-cli: ^5.0.0 => 5.0.0 
    prop-types: ^15.7.2 => 15.7.2 
    qrcode: ^1.4.4 => 1.4.4 
    qs: ^6.9.1 => 6.9.1 
    react: ^16.12.0 => 16.12.0 
    react-dom: ^16.12.0 => 16.12.0 
    react-test-renderer: ^16.12.0 => 16.12.0 
    regenerator-runtime: ^0.13.3 => 0.13.3 
    styled-components: ^5.0.0 => 5.0.0 
    stylelint: ^13.0.0 => 13.0.0 
    stylelint-config-recommended: ^3.0.0 => 3.0.0 
    stylelint-config-styled-components: ^0.1.1 => 0.1.1 
    stylelint-processor-styled-components: ^1.9.0 => 1.9.0 
    webpack: ^4.41.5 => 4.41.5 
    webpack-cli: ^3.3.10 => 3.3.10 
    webpack-dev-server: ^3.10.1 => 3.10.1 
    whatwg-fetch: ^3.0.0 => 3.0.0 
  npmGlobalPackages:
    npm: 6.13.4

Additional context
We ran into this issue when we upgraded from @aws-amplify/auth 1.3.3 to 2.1.3. The last version that works is 1.4.3, anything after 1.5.0 is not working.

Sample code
Our Content-Security-Policy:

default-src 'self';
connect-src https://cognito-idp.eu-central-1.amazonaws.com;
object-src 'none';
style-src 'self' 'unsafe-inline';
base-uri 'none';

I hope I didn't forget anything. If there's anything else I can do to make the issue more clear or to provide additional insights, please let me know.

Core bug

Most helpful comment

To avoid future issues of this type, I'd recommend ensuring the following rules are enabled:

All 6 comments

Thanks for the report and the detailed repro steps @MHarutunian

I'll be taking a look and reporting back here

I'm having the same issue. My CSP policy is "script-src 'self' 'unsafe-inline'". I do NOT want to add unsafe-eval to the CSP as it is not recommended (will also lower my Mozilla Observatory score). I am using the Amplify framework mainly for the Logger, Hub, and the i18n. Looks like GoogleOAuth and FacebookOAuth are calling browserOrNode(). I'm using aws-amplify 2.2.0

I'm having the same problem, is there any workaround here?

Something I don't understand is why are GoogleOAuth.js and FacebookOAuth.js executed? I don't use OAuth at all! šŸ¤”

I'm having the same problem, is there any workaround here?

Something I don't understand is why are GoogleOAuth.js and FacebookOAuth.js executed? I don't use OAuth at all! šŸ¤”

The libs are included bc Amplify includes the relevant libraries for Cognito. Amplify lib is not split into fine grain packages. It's all or nothing. So you may not be using Cognito but auth related code gets pulled in nonetheless.

To avoid future issues of this type, I'd recommend ensuring the following rules are enabled:

Was this page helpful?
0 / 5 - 0 ratings