Cross Origin Resource Sharing (CORS) is intended to be revolutionary, empowering the web to push and pull data from everywhere. In reality I see this causing more problems than helping anyone. Note: I’ll use XMLHTTP instead of AJAX since the latter is so overloaded…
1. It breaks the cross-domain paradigm
This is really all I have to say, Client-side, or “Front-End” was always intended as-such. Your Front-End was only allowed to talk to your Back-End, all heavy-lifting was to be done by your servers in a protected, secure environment. Your Front-end is a gateway, probably the least-secure gateway imaginable to your server-side infrastructure. The restrictions put in place we’re intended to protect your sensitive information, and ensure a secure user experience for users.
- Form POST validation – don’t respond to requests if they’re not validated as from your own servers (this is more of a convention than actual restriction)
- Same-origin policy for XMLHTTP
- Cross-domain cookie policies and restrictions.
2. It’s intended for resources
Yes, “resources” can mean anything – but think about what the original challenge was when we were doing AJAX when CORS was added to browsers? Getting mostly static-content to power single-page, rich web applications with “partial page-loads”. Getting public data from a server not on your domain using XMLHTTP. As you start to look into CORS you’ll see it defaults to allow simple loading of content with ease, without support for anything else you might come to expect from a true XMLHTTP call. These are things like authenticated requests, reading cookies to deliver personalized responses.
3. Let the servers do the talking
In the days of quad-core processors, 64-bit browsers, untouched RAM-potential and dizzying internet speeds CORS is yet another thing that cracks open the limitation(s) that made us be conscious about what we do client side.
“Great! I can finally load this cross-domain data without making a server-proxy to bring it in via XMLHTTP”
Wrong. Do you control this server? What is their response-time SLA? What if tomorrow they blow open the payload and send Megabytes back to the browser? Cross-domain lmitations and the reliance of servers to do the cross-domain talking enforced increased security between parties, and allowed for server-power to broker any issues between this data and your client-side.
4. Did you forget Node.js?
Oh, you did? Just like everyone else? Node was a fun tool that allowed us to write server-side programming in our favorite client-side orchestration language of Javascript. Asynchronous-all-the-things, even cross-domain requests! There’s a reason this was allowed, server-side. Now you can blend all of this, without using NPM, and using my browser as the server…
5. You can’t have it all.
CORS has a very specific set of restrictions in place that maintain the level of security we expect with XMLHTTP.
CORS Request | CORS Response | Domain Restriction Result (Origin) | Cookies | Notes |
– | Access-Control-Allow-Origin: * | all allowed | no | CORS everywhere |
– | Access-Control-Allow-Origin: http://yourdomain.com | http://yourdomain.com | no | CORS for a single whitelisted domain |
– | Access-Control-Allow-Origin: http://yourdomain.com, http://www.yourdomain.com | NOT ALLOWED | no | Can’t whitelist more than one |
– | Access-Cotrol-Allow-Origin: * Access-Control-Allow-Credentials: true |
all allowed | no | Will break if CORS request contains credentials |
withCredentials=”true” | Access-Cotrol-Allow-Origin: * Access-Control-Allow-Credentials: true |
NOT ALLOWED | no | Cant have wildcard origin whitelist AND allow credentials |
withCredentials=”true” | Access-Cotrol-Allow-Origin: http://yourdomain.com Access-Control-Allow-Credentials: true |
http://yourdomain.com | yes | Only way to send credentials with single whitelist domain. |
Notice if all you’re receiving is static content its easy to do across all domains, if we want to restrict CORS to a set of domains you can only do it for one, and most strict is the ability to send credentials – this includes Auth and Cookies. I found these two posts lay out the credentials issue the best:
https://quickleft.com/blog/cookies-with-my-cors/
http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api#credentials
As we think about APIs, it’s clear that CORS wasn’t designed to provide the same heavy lifting as server-API calls. API endpoints typically allow any number of Origins/hosts given they have proper permission, and usually have a pretty good auth scheme for that permissioning. How do you set up CORS, with credentials, for multiple domain-origins? You can’t, or at least you shouldn’t. The answers I’ve seen all recommend managing a whitelist server-side and setting the Access-Control-Allow-Origin origin dynamically based on the request.
6. What about JSONP?
Isn’t this why we’re here? JSONP “isn’t good enough”, or “has security holes”, or “cross site scripting vulnerabilities”. Those might all be true but in the end is CORS really any better? Lets think about JSONP:
- Allows request to be made cross-domain like any other resource
- Standard cross-domain restrictions remain in-place
- Cookies/credentials
- Can only send/receive data via GET
- You’re putting the same faith in the 3rd party as with a CORS request
To me, CORS is not a better answer to JSONP, it’s just another answer to the same problem that at the end of the day – you’re really better off handling server-side if you truly want to be secure.
7. It may be the right tool for the job.
I didn’t find anything that talked about how much CORS is used currently across the web. I did find some information that leads me to believe a lot of mobile developers rely on it for apps. I think as with most things – there’s a good set of use-cases for CORS, but that doesn’t mean it’s a silver bullet that will take the place of good ‘ol web architecture.