7

I am attempting to access my movie API that returns data including an image of a movie poster through a React application. This image is being requested from an external website. Each time I make a request to my \movies endpoint, the image is blocked and I get the following message in the console

net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep 200

When looking at the request in the Network tab, I get the following message saying to enable a Cross-Origin Resource Policy

Because your site has the Cross-Origin Embedder Policy (COEP) enabled, each resource must specify a suitable Cross-Origin Resource Policy (CORP). This behavior prevents a document from loading cross-origin resources which don’t explicitly grant permission to be loaded.
To solve this, add the following to the resource’s response header:
Cross-Origin-Resource-Policy: same-site if the resource and your site are served from the same site.
Cross-Origin-Resource-Policy: cross-origin if the resource is served from another location than your website. ⚠️If you set this header, any website can embed this resource.

I am using the CORS npm module which had previously been used to solve my issue with an Access-Control-Allow-Origin error. I added some additional middleware to try and add the header as instructed. This is the app.js server with that code

App.js

'use strict';
import express, { json, urlencoded } from 'express';
import morgan from 'morgan';
import mongoose from 'mongoose';
import passport from 'passport';
import cors from 'cors';
import dotenv from 'dotenv';
import auth from './routes/auth.js';
import routes from './routes/routes.js';

dotenv.config();

const app = express();

mongoose
    .connect(process.env.CONNECTION_URL, {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    })
    .then(res => console.log('DB Connected!'))
    .catch(err => console.log(err, err.message));

app.use(cors())

app.use((req, res, next) => {
  res.header("Cross-Origin-Resource-Policy", "cross-origin")
  next()
})

app.use(passport.initialize());
app.use(json());
app.use(urlencoded({ extended: true }));
app.use(express.static(`public`));
app.use(morgan('common'));

auth(app);
import './authentication/passport.js';

routes(app)

app.use((req, res, err, next) => {
    if (err) {
        console.error(err.stack);
        res.status(500).send('Something broke!');
    }
    next();
});

const port = process.env.PORT || 3000;

app.listen(port, '0.0.0.0', () => console.log(`Listening on Port ${port}`));

After doing this, the console throws the same error and the Cross-Origin Resource Policy still is not set. Is there something wrong with my approach or the way that I have my file structured?

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Myles Jefferson
  • 115
  • 1
  • 1
  • 5
  • #1 How is the image requested? with ajax or . #2 Inspecting in the network tab, try to find the OPTIONS request (before the image) and check if the expected headers are missing. #3 Try to load the image using pure ajax, to reproduce the error. https://gist.github.com/jrichardsz/6b6f2c0d052253f7b76a35427bdff1b9 – JRichardsz Nov 04 '21 at 02:39
  • The answer at https://stackoverflow.com/a/67267880/441757 might be useful – sideshowbarker Nov 04 '21 at 03:21
  • @JRichardsz The image is being requested with . It seems that the issue is that the headers I try sending do not get set on the responce. – Myles Jefferson Nov 04 '21 at 17:42

1 Answers1

24

You have COEP enabled in the client:

Cross-Origin-Embedder-Policy: require-corp

This is a great security feature that means:

COEP: Everything (data, images etc) on this website is mine, or I fetch from it from other websites using CORS. (There can be a third way, that is data being authorized by cookies, http-auth, etc... which is not in our discussion, so don't bother here.)

So, you have two options. The first one is to disable COEP, but I assume that you don't want to do that. So, the other option is to use CORS for everything external. For example, when you fetch something, use:

fetch('https://externalwebsite.com/image.jpg',{mode:'cors'})

or, to embed an external image in the HTML, use crossorigin

<img crossorigin="anonymous" src="https://externalwebsite.com/image.jpg">

Note that crossorigin attribute in <img> means CORS. If it is missing, it means "no-cors", which is the default. Be aware though: When you use JavaScript's fetch, the default is {mode:'cors'}, i.e. the opposite!

Now, if you try to do that (use CORS, as you should), the browser will throw another error:

Access [...] has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

That means... exactly that! That the external server has to send the header:

Access-Control-Allow-Origin: *

That setting means that every website can use the server's resources (API in your case), as long as it does not use/send/receive cookies in the request (because... security). The way to implement this in your express server is to set:

res.header('Access-Control-Allow-Origin', '*');

Every server that intends to serve things to other websites, must have this ACAO header. (You can place your other website instead of "*" if you want only that website to access your API.)

Note/Summary:

If the external server has this ACAO header, you can fetch things using CORS/crossorigin. If it does not have ACAO header, you can fetch things with no-cors / without crossorigin. But with COEP enabled in your website, you can only fetch with CORS/crossorigin, so the external server has to have an ACAO.

Now,

As for the Cross-Origin-Resource-Policy that your server has, have in mind that (https://developer.mozilla.org/en-US/docs/Web/HTTP/Cross-Origin_Resource_Policy_(CORP)):

  1. The policy is only effective for no-cors requests
  2. During a cross-origin resource policy check, if the header is set, the browser will deny no-cors requests issued from a different origin/site.

This means that, since you make only CORS requests to that server, this header doesn't do anything (in your case). So the server can set it to "same-site"/"same-origin" for security reasons that are beyond this topic.

Dim Vai
  • 726
  • 8
  • 14
  • What about scripts from a CDN? I;m getting this error because of a go middleware (https://github.com/gofiber/fiber/blob/master/middleware/helmet/helmet_test.go) – TheRealChx101 Jul 03 '23 at 18:55