Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Helmet causing MERN app hosted on heroku cause ERROR: Refused to execute inline script because it violates the following

I have hosted my MERN app on Heroku , but whenever I implement helmet in app.js file it's causing this issue.

const path = require('path');
const express = require('express');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
// const cors = require('cors');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const mongoSanitize = require('express-mongo-sanitize');
const expressSanitizer = require('express-sanitizer');
const xss = require('xss-clean');
const hpp = require('hpp');
const compression = require('compression')

const authRouter = require('./routes/authRoutes');

const app = express();
// IMPLEMENT CORS
// app.use(cors());
// app.options('*', cors());
app.use((req, res, next) => {
   res.header('Access-Control-Allow-Origin', '*');
   res.header(
      'Access-Control-Allow-Headers',
      'Origin, X-Requested-With, Content-Type, Accept, Authorization'
   );
   if (req.method === 'OPTIONS') {
      res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, PATCH, DELETE');
      return res.status(200).json({});
   }
   return next();
});

//SECURITY
// app.use(helmet());  <------causing issue.

const limiter = rateLimit({
   max: 100,
   windowMs: 60 * 60 * 1000,// 1 hour
   message: 'Too many requests from this IP, please try again in an hour!'
})
app.use('/api', limiter);

// Body parser, reading data from body into req.body
app.use(express.json({ limit: '10kb' }));
app.use(express.urlencoded({ extended: true, limit: '10kb' }));
app.use(cookieParser());
// Data sanitization against NoSQL query injection
app.use(mongoSanitize());
// HTML sanitizer
app.use(expressSanitizer());
// Data sanitization against XSS
app.use(xss());
// Prevent parameter pollution
app.use(hpp({
   whitelist: ['tags', 'likeCounts', 'commentCounts']
}));
// COMPRESSION
app.use(compression())
// logging 
if (process.env.NODE_ENV === 'development') {
   app.use(morgan('dev'));
}

App is running fine in local environment but helmet causes the ERROR:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-c8oXMAC5SpSNhKqLeKnZuBIrD93BdSvpZ47lOJrkmFE='), or a nonce ('nonce-...') is required to enable inline execution.

I also tried fixing it by following this:

  1. create a .env file in project root
  2. Add variable as follows: INLINE_RUNTIME_CHUNK=false
  3. Build the project again and load the extension again.

But it doesn't help. Please guide me how can I fix it and also what would be best way to implement other security measures in my app?

like image 806
GrimReaper07 Avatar asked Mar 01 '23 18:03

GrimReaper07


1 Answers

Helmet maintainer here.

This is happening because of something called Content Security Policy, which Helmet sets by default. To solve your problem, you will need to configure Helmet's CSP.

MDN has a good documentation about CSP which I would recommend reading for background. After that, take a look at Helmet's README to see how to configure its CSP component.

To give some help specific to this question: this error is telling you that the script-src directive of your CSP does not allow inline JavaScript, and so it was blocked.

This is considered "inline" JavaScript:

<script>console.log('hello world!')</script>

This, however, is not:

<script src="/foo.js"></script>

There are several ways to fix this:

  1. Add a hash or nonce to the inline <script> and use that in your CSP. See this example on MDN for help.

  2. Refactor your app to avoid inline scripts entirely.

  3. Update your CSP to allow unsafe inline scripts. You'd do something like this:

    app.use(
      helmet({
        contentSecurityPolicy: {
          directives: {
            ...helmet.contentSecurityPolicy.getDefaultDirectives(),
            "script-src": ["'self'", "'unsafe-inline'", "example.com"],
          },
        },
      })
    );
    

    Note that this is considered unsafe.

  4. Disable CSP. This is the most dangerous option so I don't recommend it.

    app.use(
      helmet({
        contentSecurityPolicy: false,
      })
    );
    

In summary: to solve your problem, you will need to tell Helmet to configure your CSP.

like image 200
Evan Hahn Avatar answered Mar 05 '23 15:03

Evan Hahn