
Do You Really Know CORS? - grzegorz_mirek
http://performantcode.com/web/do-you-really-know-cors
======
Klathmon
This is an awesome overview! But don't take it as all encompassing, it doesn't
go into some of the more esoteric edge cases with CORS, like:

* either an unreleased safari version, or the most recent version will send preflight requests even if the request meets the spec (like if the Accept-Language is set to something they don't like).

* If you use the ReadableStream API with fetch in the browser, a preflight will be sent.

* If there are any events attached on the XMLHttpRequestUpload.upload listener, it will cause a preflight

* cross-domain @font-face urls, images drawn to a canvas using the drawImage stuff, and some webGL things will also obey CORS

* the crossorigin attribute will be required for cross-origin linked images or css, or the response will be opaque and js won't have access to anything about it.

* if you mess up CORS stuff, you get opaque responses, and opaque responses are "viral", so they can cause entire canvas elements to become "blacklisted" and extremely restricted.

I feel like I've cut my teeth on this API more than most, and I still feel
like I'm only scratching the surface!

~~~
laumars
The entire webstack is such a broken mess of inconsistencies and thousands of
hidden traps that can render the entire thing insecure.

People moan about C yet I find the web stack greatly more painful to write
because you didn't even have control over the compiler following standards
strictly (where stuff has even been standardised).

I really do wish we worked together to create a new standard for building and
deploying documents and applications over the internet because this HTML (and
all its supporting technologies) is an experiment that has gone bad. Id
preferably want something that doesn't allow each browser to interpret the
specifications differently and absolutely something that isn't controlled by
Google (they would obviously need input but the last thing we need is another
AMP).

Of course it will never happen, but one can dream / rant nonetheless.

~~~
pjc50
The web is the state it's in because it's a no-mans-land between warring
proprietary vendors. Any one of Apple, Microsoft, or Google (even secondary
players like Amazon, Oracle, or Valve) would much prefer a world in which they
had the dominant platform and could get a 30% cut and arbitrary veto over all
software written for that platform.

~~~
laumars
The problem you describe does exist but I respectfully disagree that's the
reason why writing web applications has become as cumbersome as it has. I
think the issue there is more down to standards authorities being glacially
slow to recognise the change in demands. This has obviously allowed a
situation where browser vendors such as Microsoft and Google have felt they
needed to run amok just to offer many of the features developers were asking
for (and to an extent, consumers too since end users were lured in by prettier
and more interactive sites).

There have been other examples in history where programming languages used to
differ - sometimes even significantly - depending on which compiler / platform
you were targeting and where a standards body later stepped in to create a
basic subset of said language that should be universal across all dialects
(please note they cannot enforce this). In those instances that has lead to
code to become greatly more portable.

To some extent, this is now happening with the web as well; however my
secondary point to the complaint about differing outputs between browsers is
that I believe HTML et al is a lousy way to design applications from the
outset. That definitely is not a problem created by warring proprietary
vendors or slow revisions of standards but rather just an artefact of
technology evolving past it's original purpose yet still having to retain
backwards compatibility. Maybe the time has come that we need a second
language for the web so we have HTML et al for legacy applications, blogs and
other stuff that is following some of the original visions of the web, but
have a new language for web applications and anything that requires a stronger
security model.

------
3pt14159
I'm ideologically against third party on the web because it is a privacy
nightmare. But I'm in the system that I'm in, and I don't take on fights that
aren't possible to win, so barring my becoming a billionaire I've kinda just
accepted that third party is here for at least a little while and I'm not
going to refuse to use ads and analytics. Except on my personal website, that
gets to stay cool.

That said, CORS is the only thing about third party that I actually like. It's
secure by default. That the ensure header and accept header are different
things is amazing. I know all about the performance issues[0], but I'm ok with
it in the right context.

[0] It's kinda funny how against the herd I am here. I think it is shitty that
the preflight sometimes _doesn 't_ happen. It's so weird to me that we carved
out exceptions for this and seems like an otherwise secure-by-default system
should have come with the guaranteed preflight.

~~~
paulddraper
CORS is not necessarily about third parties.

It's common to have app.example.org point to a CDN and api.example.org point
to an API.

And CORS implementation is terrible. The server has to transmit validation
rules for the browser to enforce (with vendor specific caching differences),
rather than just enforcing access itself.

The reason it's implemented this way is because of the organic evolution of
web security.

~~~
ravenstine
> rather than just enforcing access itself.

Could you elaborate on that? I can't picture the alternative you're
suggesting.

~~~
paulddraper
The alternative is for the idea agent to send the Origin header on all
requests.

Then the server responds with 200 or 403.

~~~
mattnewton
The people with the security problem are the users of browsers, and the
browser vendors have a solution to solve that problem built into the browser.
If they didn’t enforce it at the browser level, the owners of the servers
would have little incentive to enforce CORS and most just wouldn’t. See https
adoption.

~~~
johncolanduoni
Bingo. I still kind of wish there was an ability to make the browser invoke
some kind of request that servers would reject by default (e.g. with a non-
standard HTTP method) that could combine the preflight check and the request
while still making servers that don’t anticipate CORS blanch and not take any
dangerous actions. But the browser security model is complex and messy enough
as it is, so I doubt it’s worth it.

------
Thu27Sep
One idea that the article doesn't convey well, in my opinion, is that the
Same-Origin Policy only prevents the browser from _reading_ the response from
an HTTP server to third-party host, but it doesn't prevent the request from
being issued in a first place. The CORS headers are merely a way for the
server to indicate to the browser whether it is allowed to read the response
of not, but it doesn't protect the server from anything.

Especially, setting the "Access-Control-Allow-Credentials" header to true
means that a client which sent a request with a cookie is allowed to read the
result, but whether the request is sent with a cookie or not, and will be
treated as such by the server, is entirely up to the client.

So although malicious.com cannot read the details of bank.com using AJAX, it
can definitely send a POST request to trigger the transfer from the user's
account to a malicious account using the user's cookie (blindly so).

This is the reason proper CSRF protection must be implemented by the server,
independently of whether CORS is enabled or not.

~~~
sbergot
This is not entirely true. The preflight's role is exactly to prevent a post
request to be sent to the server. There is no preflight only in particular
cases.

~~~
Thu27Sep
This is entirely false. POST requests with headers set automatically by the
user agent aren't preflight-ed. There is a preflight only in particular cases.

------
waffle_ss
I recently implemented a feature that depends on CORS and I don't see anything
in this article that adds any value over Mozilla's thorough CORS docs.[1]

If you're writing an article on CORS today I also think you should mention
recent CORS developments such as Cross-Origin Read Blocking (CORB)[2] and
features on the horizon such as Cross-Origin-Resource-Policy, Cross-Origin-
Window-Policy, etc. that in light of Spectre, Meltdown etc. are meant to help
plug speculative execution holes.[3]

[1]: [https://developer.mozilla.org/en-
US/docs/Web/HTTP/CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)

[2]: [https://www.chromium.org/Home/chromium-security/corb-for-
dev...](https://www.chromium.org/Home/chromium-security/corb-for-developers)

[3]: [https://www.arturjanc.com/cross-origin-
infoleaks.pdf](https://www.arturjanc.com/cross-origin-infoleaks.pdf)

------
emmelaich
> _performantcode.com took too long to respond. ERR_CONNECTION_TIMED_OUT_

Too ironic not to mention.

------
lwansbrough
I love CORS. I wouldn't be able to provide the level of security with my API
that I do because of it. Without CORS, I don't believe my API design would be
practically possible due to the security risks.

If I have access to the Fetch API, I can tell the browser to send the user's
cookie cross-origin and I can validate the request based on the origin. This
allows for interesting authentication scenarios without the need for explicit
client-user consent pages.

~~~
acoard
>and I can validate the request based on the origin

Are you talking about the HTTP referer? That's easily spoofable and can't be
relied on server-side. The same-origin policy and all the CORS security is
implemented in the browser itself, not in HTTP.

If you need to be certain that a request originated from your own page and not
another domain you need to use a CSRF token.

~~~
lwansbrough
I'm talking about the Origin header, which is present on XHR requests and
cannot be assigned by code. A CSRF token is not necessary if you require
Origin because the origin is not sent with standard HTML forms.

~~~
graphememes
It can be inside of insecure browsers, you're not any more secure than you
were before after CORS.

~~~
lwansbrough
Users with insecure browsers are subjecting themselves to security
vulnerabilities, not me. In this case, the service just wouldn’t work for
them. Not overly worried about those users because they represent a
diminishingly small portion of our user base.

~~~
graphememes
The problem is that you can be unaware. It's also not tracked as a metric.
Nobody knows how large or small it is.

Also, it's easily bypassed.

------
JepZ
I never really understood why we have CORS. I mean, the problem with CSRF is
that some random page can trick your browser into adding its authentication
token to a request which does not originate from the authenticated page. So
why the do we need the server to tell the browser that it should not send
requests from other origins?

In my opinion, it would have been much better to improve the browsers to not
include cookies in 3rd party requests automatically (only when they are
explicitly specified via JS for example). It should have solved the issue
equally well, without introducing some bulky server-side security feature to
remote control browsers.

~~~
zackmorris
Ya I generally think CORS is a waste of time. It would have been better to
provide a hash of the file we're linking to and trust that rather than where
it came from. Which is precisely what Subresource Integrity (SRI) does:

[https://en.wikipedia.org/wiki/Subresource_Integrity](https://en.wikipedia.org/wiki/Subresource_Integrity)

Sadly even though this is an obvious concept and trivial to implement, it took
them over 20 years since the web came out to get it in most browsers. The cost
to society of having thousands of copies of the same commonly used files (like
jQuery) hosted locally on countless servers rather than having a centrally
hosted version already cached from previously visited sites is staggering to
contemplate. I'd really like to know who was behind the holdup on deploying
SRI.

~~~
iancarroll
CORS is about a lot more than just static assets. SRI does not replace CORS.

------
guscost
CORS is a technical subsidy granted to (sloppy) users of cookie
authentication. I’ve never worked on a project where it was anything other
than an annoying hoop to jump through.

~~~
matt4077
When has "subsidy" become the go-to narrative to argue against any sort of
deference to real-world usage?

You could just as easily frame CORS as "antibiotics for the people who dared
to leave their house".

(There's also a no-true-scotsman fallacy going on in your argument)

~~~
guscost
More like "mandatory medical testing at the airport because some people don't
vaccinate" from my perspective.

It's a "subsidy" because we all have to spend time on it, even though lots of
people don't receive any benefit from it. It's not intolerable, the Web is
based on community standards and responds to community needs, and I'm fine
with that. But I'm always on the losing end of this one so I'm going to say
so.

------
parhamn
Im curious how many newer JS+API applications still use browser cookies as a
means of authenticating API requests and how prevalent cookie usage still is
for these types of applications?

JWT/tokens + Local/session storage + adding fetch headers seems like the best
way as long as you don't run untrusted JS.

~~~
anthuswilliams
"as long as you don't run untrusted JS" is a surprisingly tough hurdle to hit,
even for very experienced developers.

What is your reason for preferring JWT + localStorage for authentication and
session handling? I'm genuinely curious, as httpOnly cookies strike me as
better in every meaningful way.

------
valtism
Mirror:
[https://web.archive.org/web/20181004000006/http://performant...](https://web.archive.org/web/20181004000006/http://performantcode.com/web/do-
you-really-know-cors)

~~~
zero_kool
You the MPV!

------
stesch
Had to deal with a firewall that filtered all unknown/"new" HTTP headers. This
included CORS.

A PITA to find the reason why Firefox wouldn't use the Google fonts.

~~~
crooked-v
That kind of crapware is why I'm increasingly glad that the http specs are
moving towards being completely illegible to middleware boxes.

~~~
edoceo
How would http be any harder for middleware than app-layer? If both linked to
libhttp.c, couldn't they each get the full parsing/reading/writing - wether
proxy or server?

~~~
crooked-v
Being able to parse HTTP doesn't get anywhere when you can't actually get at
the contents because they're encrypted (as with all major HTTP2
implementations).

~~~
stesch
[https://www.howtoforge.com/filtering-https-traffic-with-
squi...](https://www.howtoforge.com/filtering-https-traffic-with-squid)

[http://www.watchguard.com/help/docs/wsm/xtm_11/en-
us/content...](http://www.watchguard.com/help/docs/wsm/xtm_11/en-
us/content/en-us/certificates/cert_https_proxy_resign_c.html)

------
lysium
This is really an informative article. We've recently stumbled across this
issues and all other pages I could google did not explain it as clearly as
this page.

~~~
ottomanage
My experience was the same as yours, resources explaining things assumed
technical knowledge far beyond my level or were not very clear. This was a
very well put-together article.

My only contribution to the discussion is that if you get a CORS error where
you wouldn't expect it, the problem might not be a CORS issue. I spent the
better part of a weekend trying to debug why a request to a Google API wasn't
working and why I was seeing a CORS error (same thing worked fine on another
system). Turns out, it wasn't the same thing, my url had a typo...

~~~
jchook
You may also enjoy [https://hackernoon.com/im-harvesting-credit-card-numbers-
and...](https://hackernoon.com/im-harvesting-credit-card-numbers-and-
passwords-from-your-site-here-s-how-9a8cb347c5b5)

------
denormalfloat
Why not just include the Origin on all cross-origin requests? Then the server
could deny/allow it without the need for preflight.

~~~
jraph
I would be concerned about the privacy implication of it. Imagine if the
browser sent the origin to widely used CDNs, or to Google Fonts, and that
people didn't actually block Google domains on their browsers.

Also, this would not be secure by default, because you would have to change
the default behavior of the server to block cross origin requests.

~~~
kijin
Browsers already send the referer header on all those CDN requests, provided
that the CDN is loaded over https. If anything, the origin contains less
information.

------
dvdcxn
How do you prevent people proxying your API via a node service?

This is something I could never get my head around with CORS - what's the
point of whitelisting origins if getting around the whitelist is nothing more
than an inconvenience?

~~~
Liquidor
CORS is mostly used to prevent attacks from a browser script on a non-
whitelisted website (CSRF etc.).

To prevent someone abusing your API otherwise, use an authentication method.

------
bluepnume
I built out [https://github.com/krakenjs/fetch-
robot](https://github.com/krakenjs/fetch-robot) to avoid some of the esoteric
issues around CORS endpoints -- and to avoid the performance hit of that
preflight request.

It acts as a `fetch` implementation that allows you to declare cross-origin
policies in advance, then channel the requests through an iframe which
enforces those policies.

------
afs35mm
Here's one question that's always bugged me - What's stopping a malicious user
from sending an HTTP request from any API client like Postman, or even Curl
from the CL? Something like a post with: {transferTo: myAccountId, amount:
1000000000}?

Obviously in any nontrivial web app it would fail because of authentication
issues, but if a server doesn't do ANY sort of security checking, that should
work, no? Does that mean that the onus is on the server developer of
mybank.com? And if so, what would stop the malicious request from working on
any server developed before the existence of CORS?

~~~
joevandyk
Server is supposed to check authentication/authorization through some method.

If HTTP, that’s done via setting some information in the request headers, be
it a cookie, or basic auth, or token auth, or similar.

CORS is done by the browser - to not allow certain requests to be made (In
case you are accidentally executing malicious javascript code). The server
tells the browser via the CORS headers which requests are ok to make.

------
jedberg
My only experience with CORS has been when trying to access api.foo.com from a
web page on foo.com, and then getting denied. Then I messed with the settings
on api.foo.com trying to get it to allow access from foo.com, and then I gave
up and just configured the load balancer on foo.com to proxy requests to
foo.com/api to api.foo.com.

So far it's only gotten in my way as a developer. But it's there to protect
users, not me. So at the end of the day, I'm glad it's there as a way to
somewhat prevent people from tricking my users into hitting my api with
malicious requests.

~~~
dasil003
You have it backwards. This type of request was not possible at all before
CORS, CORS is what allows you to make it possible.

------
stockkid
very nice article. I thought I understood CORS but learned some new things:

* not all cross origin requests need to be preflighted * to use credentials, server needs to explicitly allow credentials to be sent from client

------
exabrial
No... I don't despite my best efforts to be diligent about learning it. :(
It's a workaround for a bunch of compromises we made where the cure is almost
not worth the pain.

------
otabdeveloper2
> Do You Really Know CORS?

Of course I don't, nobody does.

------
officialchicken
I know it well enough that changing to a custom mime-type like "text/x-myapp-
foo" is a solution that gets around CORS and pre-flight as well in the latest
version of Chrome.

~~~
Klathmon
Are you sure? That's a pretty insane security issue if it's true!

Content-Type should only be allowed to be `application/x-www-form-urlencoded`,
`multipart/form-data`, or `text/plain` to be allowed without preflight.

Edit: I can't reproduce this on Chrome 69.0.3497.100 (Official Build)
(64-bit). Setting the Content-Type to anything other than the above with a
POST request will cause an OPTIONS preflight, even when using your example.

~~~
officialchicken
I'm using 69.0.3497.81. Make sure your server accepts the header... after
changing I stopped seeing OPTIONS requests in my server logs, not that it
measurably improved the speed of the SPA. It was several months ago I made the
change and FF behavior is definitely different (more relaxed?) than Chrome
when it comes to CORS.

~~~
TeMPOraL
There's caching for successful preflights; maybe it's involved here?

------
uyuyhay
Please explain why browsers can't request and use any url as a regular curl
command does (I'm explicit talking about request without sending browser
cookies)

~~~
Ajedi32

        curl http://192.168.1.1/
    

Every site you visit would have unauthenticated read access to internal
servers on your LAN, such as your router's home page.

~~~
Moru
Or your printers admin interface. Or your NAS.

------
legohead
You think you know CORS, and then your users visit your site with the Edge
browser...

------
jaequery
I tend to use jsonp to get out the cors restriction time to time

~~~
wingi
But jsonp have to be supported by your extern API.

------
vks2108
the link is not working for me. Is there an alternative link.

~~~
toonitw
[https://dzone.com/articles/do-you-really-know-
cors](https://dzone.com/articles/do-you-really-know-cors)

------
jhabdas
I don't know CORS that well, but like any dev worth their weight in salt I
know how to get around it:

\- iframe \- domain js hack \- reverse proxy \- http header

What else? Referrer Policies await.

~~~
jpangs88
I agree, the only thing I have ever found with CORS is that it makes it
difficult for people who don't consider it when planning out servers should
run. It goes like this:

\- Just use my API...

\- I tried, please enable CORS.

\- What's CORS?

I find it frustrating that this seems to be the default for most servers. I
think it should be opt in and not opt out.

~~~
dasil003
In order to make it opt-in you’d need to disable cookies by default (at least
for auth) or else you get massive pwnage by default.

------
stillbourne
I am very upset that no one said "Of CORS I do!"

