0

I am having problems to understand which component has to sent which headers in what cases:

I have the following components

  1. Browser: local, displays website

  2. Webserver: remote, apache, serves http-website at port 80

  3. REST-Server: remote, custom implementation in golang, serves resources at port 8080 and offers three types of ressources

    /api/login (POST)
    /api/foo (GET)
    /api/bar/0/sub/1 (GET and POST)

Everything worked fine as long as I had the whole CORS setup working with localhost only. But now that I try to execute on the remove server I get CORS violations.

Most of the online documentation discusses what browser and server should do, but which of the servers (website vs. rest) has to do what?

Question: who has to set which Access-Control-Allow-Origin-Headers to post a login-request?

Beginner
  • 5,277
  • 6
  • 34
  • 71
  • 2
    new specs, I don't have details while not being actively in web dev, but since last year proper headers should be provided by source server, legacy method shouldn't work (should be blocked by browser). That's why Chrome broke quite a number of content-forwarding websites last year ironically, that included some regional Google's servers) – Swift - Friday Pie Feb 16 '20 at 14:23
  • 2
    CORS is easier to understand when you recall that it's not intended to protect resources, but to help browsers protect users against malicious websites. So the resource you want to access (the REST API) must set CORS headers to allow access by the website. But if all parts are under your control I'd rather set up a reverse proxy to serve the website + API from the same origin. – amon Feb 16 '20 at 17:13
  • @amon ok, this helps. Could you please post this as an answer? – Beginner Feb 16 '20 at 17:41
  • 1
    @Beginner I've stopped writing answers[,](https://meta.stackexchange.com/q/333965) but would of course welcome if anyone turns the comments into a full answer. I don't know how much traffic from answerers a secondary tag like [tag:cors] sees though. – amon Feb 16 '20 at 21:01
  • Read the error message you receive. It tells you precisely what is missing for the request to be successful. – Kevin B Feb 17 '20 at 19:27

1 Answers1

1

The following notes gathered from various sources helped me as a CORS beginner (which I still most definitely am) - so, maybe they will also help others.

Also, I am sure the following notes are far from the full story. And like @amon said, reverse proxying is also a way to solve for (i.e. sidestep) CORS.

1) That CORS Flowchart

See this question - the flowchart shown there is a summary describing who sends what. However, as a beginner, I found the flowchart initially difficult to understand in isolation.

I looked at this guide, which provides a lot more technical details on who can send which headers. For example, the second of its three scenarios shows who sends what for a request which includes a preflight request:

enter image description here

Three examples where preflighting is required are:

  • the request includes an authentication token
  • custom headers are included in the request
  • the request is an ajax call containing a JSON or XML payload.

In contrast, requests containing plain GETs are not preflighted.

One key point here is it is the browser - not the client application - which manages these interactions from the browser to the server. The client application has no direct involvement in these interactions.

On the server, it is typically a CORS filter which controls the contents of the response from the server back to the browser (an example is provided below).

That might be all you need to get a reasonably complete answer to the "who sends what" question. But I was still confused.

I looked at an example, which helped me much more - see below.


I think the best insight I had, along the way, was that my client application did not need to do anything specific to address CORS restrictions. It was the browser in which my application was running which took care of client-side CORS handling. As @amon says, CORS is not intended to protect resources, but to help browsers protect users against malicious websites.


2) An Example

Looking at a specific example helped my understanding of who sends what.

Scenario: We have a client application running in a browser, at https://domainA.com. It makes an API request to an unrelated server (http://anotherdomainX.net).

The example server I show here is Tomcat - other servers may have significantly different ways of configuring a CORS filter (I don't know). But the Tomcat example lays out a lot of the details in a relatively clear way.

See this ServerFault question for the example.

This is the XML from that example:

<filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    <init-param>
        <param-name>cors.allowed.origins</param-name>
        <param-value>
            http://domainA.com,
            https://domainA.com,
            http://localhost:4200
        </param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.methods</param-name>
        <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
    </init-param>
    <init-param>
        <param-name>cors.allowed.headers</param-name>
        <param-value>
            Content-Type,
            X-Requested-With,
            Accept,
            Accept-Encoding,
            Accept-Language,
            Origin,
            Access-Control-Request-Method,
            Access-Control-Request-Headers,
            Connection,
            Host,
            authorization
        </param-value>
    </init-param>
    <init-param>
        <param-name>cors.exposed.headers</param-name>
        <param-value>
            Access-Control-Allow-Origin,
            Access-Control-Allow-Credentials
        </param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

(For Tomcat, this is added to the web.xml config file in CATALINA_HOME/conf.)

The various sections in the above filter are documented here (Tomcat 9).

But the key point is it is the above filter definition which controls what specific CORS-related are returned from the server.

The cors.allowed.origins section is where the whitelist is defined. By default, the list is empty, meaning no requests get through, except those from the same domain (origin) as the server - http://anotherdomainX.net.

3) Origin Names

This is basically what you see in the address bar of your client web-based application. It has to include the protocol, domain name and port number (if used). The root of the application context is not part of the origin name.

So, for a URL such as https://domainA.com/myapp/getdata, then https://domainA.com is the origin name.

4) Postman

This appears to crop up fairly frequently. Why does my API call work in Postman, but not from my web client?

The basic answer is because Postman is a dev tool, not a browser.

My understanding is that it uses browser extensions, which have different rules regarding how XMLHttpRequests are handled.

Tools such as cURL are also not relevant for CORS because again as @amon says, CORS is not intended to protect resources, but to help browsers protect users against malicious websites.

5) null Origins

An example of a null origin is when you create a simple web page in a text file, open it in a browser, and have a URL like this:

file:///C:/temp/test.htm

Here the protocol is file:. See here for notes and warnings about this.

6) Public APIs

It's probably bad form for an answer to contain a question, but...

How do publicly available services handle CORS? Do they just enable "everyone" in their cors-allowed-origins?

<init-param>
    <param-name>cors.allowed.origins</param-name>
    <param-value> * </param-value>
</init-param>

I guess the answer is yes. In its "common pitfalls" section, the linked article states:

CORS is a relaxation of same-origin policy while attempting to remain secure. Using * disables most security rules of CORS. There are use cases where wildcard is OK such as an open API that integrates into many 3rd party websites.


I would be delighted to edit the above notes to correct any errors, if that is appropriate.

andrewJames
  • 19,570
  • 8
  • 19
  • 51