Cross-origin HTTP requests

What is it?

  • Browser mechanism for preventing requests of third party  resources for an origin
  • Enables a more controlled environment for resources by restricting origins with an access list
  • Gives us a way of disabling certain features on our resources depended on their origin

A dictionary

  • Request - an action a browser makes to get or send data to an endpoint, it can contain a payload
  • Simple request - a request not triggering preflight check
  • Header - "arbitrary" key value pairs sent with every HTTP request

When is it triggered?

  • When you are requesting a resource that is not on the same domain as the origin (eg. localhost and staging API)
  • When you are requesting a resource from an unlisted endpoint (eg. anywhere else except on app.example.org)

Preflighted requests

When are you going to get flagged?

  • If you are not using GET, POST, or HEAD 
  • If you are using any custom headers apart from Content* and a like (full list on MDN) 
  • If you are not using standard Content-types (application/x-www-form-urlencoded, multipart/form-data, text/plain)

What's gonna happen to me?

  • An OPTIONS request is sent out to determine the security of our request
  • If everything goes right (you have correct headers set on the response) a second request is going to be made
  • If the request fails an exception occurs 

Configuring CORS by the book

Setting the correct headers

  • Access-Control-Allow-Origin - comma separated list of domains (wildcards allowed)
    • Access-Control-Allow-Origin 'app.example.org'
  • Access-Control-Allow-Methods - comma separated list of methods
    • Access-Control-Allow-Methods 'GET, OPTIONS'
  • Access-Control-Allow-Headers - any custom request headers needed
    • Access-Control-Allow-Headers 'X-Bearer'
  • Access-Control-Expose-Headers - any custom response headers needed

Where do I set it?

  • On your web server (Apache, Nginx)
  • On app level (express, koa)
  • Both

How?

https://enable-cors.org/server.html

Developing with a
ill-configured CORS

Easiest solution

fetch('https://httpbin.org/get', {
    method: 'GET',
    mode: 'no-cors'
}).then((e) => {
    // type: 'opaque'
    // body: 'null'
});

Browser

  • Kill all instances of Chrome running (same version of, you can have this on Canary only e.g.)
  • Run that same version from terminal with flag
    --disable-web-security
  • ⚠​ DO NOT SURF THE WEB USING THIS

Remote Proxy

  • Prefix all requests with
    https://cors-anywhere.herokuapp.com/
  • Dirty hack
  • Maybe violating NDA (uncontrolled resource where the data is passing thru)

Webpack dev server

proxy: {
  "/api": {
    target: "https://api.example.org",
    secure: false, // can even turn HTTPS certificate validation off
    pathRewrite: {"^/api" : ""}
  }
}

Local Proxy

const httpProxy = require('http-proxy');

const proxy = httpProxy
  .createProxyServer({
    target: 'https://api.example.org',
    secure: false
  })
  .on('proxyRes',
    (_, req, res) => {
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
      res.setHeader('Access-Control-Allow-Headers', 'HTTP_USER_AGENT');
      res.setHeader('Access-Control-Expose-Headers', 'X-API-authentication-token');
    }
  )
  .listen('3010');
Method Secure No coding No Sep. Srv. Scalable
Changing mode yes no * yes no
Browser no yes yes yes
Remote proxy no yes yes yes
Webpack dev server yes no yes yes
Local proxy yes no no yes

Conclusion

  • You need and want CORS on all resources
  • Configure CORS with development in mind only on staging servers
  • Follow the standard and set all of the needed headers to reduce issues and debugging
  • Use a local proxy whenever possible for development
  • Easiest way to configure CORS for production is not to touch anything (use reverse proxy on Apache/Nginx)
  • Don't disable security in your browser
  • Stop guessing what's needed for a request to go thru and read up
  • Remember it's a browser thing - it won't stop randos

References and resources

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
  • https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
  • https://enable-cors.org/server.html
  • https://webpack.js.org/configuration/dev-server/
  • https://www.w3.org/TR/cors/
  • http://www.test-cors.org/ (mind the NDA tho)

CORS

By Andrei Zvonimir Crnković

CORS

Everything you wanted to know about CORS but were to lazy to Google

  • 134
Loading comments...

More from Andrei Zvonimir Crnković