react-universally
Version:
A starter kit for universal react applications.
126 lines (113 loc) • 4.79 kB
JavaScript
import uuid from 'uuid';
import hpp from 'hpp';
import helmet from 'helmet';
import config from '../../config';
const cspConfig = {
directives: {
childSrc: ["'self'"],
// Note: Setting this to stricter than * breaks the service worker. :(
// I can't figure out how to get around this, so if you know of a safer
// implementation that is kinder to service workers please let me know.
connectSrc: ['*'], // ["'self'", 'ws:'],
defaultSrc: ["'self'"],
imgSrc: [
"'self'",
// If you use Base64 encoded images (i.e. inlined images), then you will
// need the following:
// 'data:',
],
fontSrc: ["'self'"],
objectSrc: ["'self'"],
mediaSrc: ["'self'"],
manifestSrc: ["'self'"],
scriptSrc: [
// Allow scripts hosted from our application.
"'self'",
// Note: We will execution of any inline scripts that have the following
// nonce identifier attached to them.
// This is useful for guarding your application whilst allowing an inline
// script to do data store rehydration (redux/mobx/apollo) for example.
// @see https://helmetjs.github.io/docs/csp/
(req, res) => `'nonce-${res.locals.nonce}'`,
// This is a know workaround for browsers that don't support nonces.
// It will be ignored by browsers that do support nonces as they will
// recognise that we have also provided a nonce configuration and
// use the stricter rule.
"'unsafe-inline'",
],
styleSrc: [
"'self'",
// Webpack generates JS that loads our CSS, so this is needed:
"'unsafe-inline'",
'blob:',
],
},
};
// Add any additional CSP from the static config.
const cspExtensions = config('cspExtensions');
Object.keys(cspExtensions).forEach((key) => {
if (cspConfig.directives[key]) {
cspConfig.directives[key] = cspConfig.directives[key].concat(cspExtensions[key]);
} else {
cspConfig.directives[key] = cspExtensions[key];
}
});
if (process.env.BUILD_FLAG_IS_DEV === 'true') {
// When in development mode we need to add our secondary express server that
// is used to host our client bundle to our csp config.
Object.keys(cspConfig.directives).forEach((directive) => {
cspConfig.directives[directive].push(`${config('host')}:${config('clientDevServerPort')}`);
});
}
// Attach a unique "nonce" to every response. This allows use to declare
// inline scripts as being safe for execution against our content security policy.
// @see https://helmetjs.github.io/docs/csp/
function nonceMiddleware(req, res, next) {
// eslint-disable-next-line no-param-reassign
res.locals.nonce = uuid.v4();
next();
}
const securityMiddleware = [
nonceMiddleware,
// Prevent HTTP Parameter pollution.
// @see http://bit.ly/2f8q7Td
hpp(),
// The xssFilter middleware sets the X-XSS-Protection header to prevent
// reflected XSS attacks.
// @see https://helmetjs.github.io/docs/xss-filter/
helmet.xssFilter(),
// Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
// @see https://helmetjs.github.io/docs/frameguard/
helmet.frameguard('deny'),
// Sets the X-Download-Options to prevent Internet Explorer from executing
// downloads in your site’s context.
// @see https://helmetjs.github.io/docs/ienoopen/
helmet.ieNoOpen(),
// Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
// to guess (“sniff”) the MIME type, which can have security implications. It
// does this by setting the X-Content-Type-Options header to nosniff.
// @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
helmet.noSniff(),
// Content Security Policy
//
// If you are unfamiliar with CSPs then I highly recommend that you do some
// reading on the subject:
// - https://content-security-policy.com/
// - https://developers.google.com/web/fundamentals/security/csp/
// - https://developer.mozilla.org/en/docs/Web/Security/CSP
// - https://helmetjs.github.io/docs/csp/
//
// If you are relying on scripts/styles/assets from other servers (internal
// or external to your company) then you will need to explicitly configure
// the CSP below to allow for this. For example you can see I have had to
// add the polyfill.io CDN in order to allow us to use the polyfill script.
// It can be a pain to manage these, but it's a really great habit to get
// in to.
//
// You may find CSPs annoying at first, but it is a great habit to build.
// The CSP configuration is an optional item for helmet, however you should
// not remove it without making a serious consideration that you do not
// require the added security.
helmet.contentSecurityPolicy(cspConfig),
];
export default securityMiddleware;