helmetjs / helmet

Help secure Express apps with various HTTP headers

Home Page:https://helmetjs.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Recommended settings for use with a cdn

marnixhoh opened this issue · comments

I have been trying to find an answer to this question, which I have found, but it requires me to completely disable CORP:
crossOriginResourcePolicy: false

Due to security concerns, I'd rather not completely disable it, if possible.

I am running an Express app with helmet. The frontend (Next.js) loads all images from a CDN in production. However, these images are blocked in development (locally) with the following error in the console: err_blocked_by_response.notsameorigin 200 (ok).
Frontend is served from localhost:3001
Backend and CDN are served from localhost:3000

Note that in order for the frontend and backend to work together, CORS is openend up in development using:

mainApp.use(
    cors({
      credentials: true,
      origin: /.*/,
    })
  );

The following is my helmet config (5.1.1):

mainApp.use(
  helmet({
    contentSecurityPolicy: {
      useDefaults: true,
      directives: {
        'script-src': ["'self'", 'maps.googleapis.com'],
        'img-src': [
          "'self'",
          'data:',
          'maps.gstatic.com',
          '*.googleapis.com',
          '*.ggpht',
          process.env.CDN_HOST.split('//')[1],
        ],
      },
    },
  })
);

Does anyone have an idea as to why the images are not being loaded?

PS I am aware of this SO thread and a similar Github issue:
https://stackoverflow.com/questions/70752770/helmet-express-err-blocked-by-response-notsameorigin-200

But unfortunately disable crossOriginEmbedderPolicy does not work for me.

I hope it's ok for me to post this question here. Thank you so much for any help :D

I'll give this a more thorough look soon, but:

  • Does the CDN work in production? Is this only a problem in development?
  • Does it work if you disable Helmet completely?

Hi @EvanHahn. Thank you so much for your quick reply. I can not stress enough how much your help is appreciated :D

To answer your questions:

  • Yes it does work in production. In other words, we don't have to set crossOriginResourcePolicy: false there to make it work.
  • Yes it does work when we disable Helmet completely.

The reason we would like to use the exact same config, is to make sure our dev and production environments are as similar as possible. However, if this turns out to not be possible it wouldn't be the end of the world. But I am very curious as to why it doesn't work in development?

Thanks again :)

Short answer: I think this is happening because your development CDN needs to set the Cross-Origin-Resource-Policy header to cross-origin.

To understand this, you need to understand the concept of an embedder and the concept of a resource.

The embedder is the page you're looking at. The resource is a thing (like an image) on the page loaded from somewhere. In this case, your main app is the embedder. The image on the CDN is the resource.

When the browser sees a resource that's trying to load from a different origin, it consults the embedder's cross-origin policy and the resource's cross-origin policy. If the policies are compatible, the resource will load! If they're not, the resource will be blocked.

By default, these policies are permissive. If nobody sets any cross-origin policy headers, everything should load just fine.

But if the Cross-Origin-Embedder-Policy header is set to "require-corp", then the resource has to set Cross-Origin-Resource-Policy: cross-origin header (or use CORS) for the browser to allow it.

I think something like that is happening here. Your main app is probably setting Cross-Origin-Embedder-Policy: require-corp. Your local CDN isn't setting Cross-Origin-Resource-Policy: cross-origin but your production CDN is, which is why things only load in production.

I recommend solving this by setting the Cross-Origin-Resource-Policy: cross-origin header on your development CDN, but you can also solve this by disabling crossOriginEmbedderPolicy in development.

(I'm considering changing this in future versions of Helmet because it's caused so many issues, but I hope this answers your question for now.)

I'm going to close this issue because I think that answers your question, but let me know if you need additional help.