82
votes

I am developing a JSON/REST web API, for which I specifically want third party websites to be able to call my service through AJAX. Hence, my service is sending the famous CORS header:

Access-Control-Allow-Origin: *

Which allows third party sites to call my service through AJAX. All fine so far.

However, a subsection of my web api is non-public and requires authentication (pretty standard stuff with OAuth and an access_token cookie). Is it safe to enable CORS on this part of my site as well?

On the one hand, it would be cool if third party websites could have ajax clients that also interact with this part of my service. However, the reason that there is a same origin policy in the first place, is that this might be risky. You don't want any website that you visit afterwards to be able to access your private content.

The scenario that I am afraid of is that a user logs in on my web api, either on the website or through a website that he trusts, and he forgets to logout. Will this allow every other website that he vists afterwards to access his private content using the existing session?

So my questions:

  • Is it ever safe to enable CORS on non-public content?
  • If a CORS enabled server sets a session_token through a cookie, will this cookie be saved under the domain of the CORS server or main web-page server?
2
Note that you could only send the CORS headers on the resources that you want others to access from other origins. And you could also limit CORS access to only the origins that you expect usage from.Dan D.
Idealy, I would like all resources to be accessible from any origin, if security permits. It is still up to the user to provide valid credentials. I just want to make sure I am not opening the door for cross-site scripting attacks from malicious websites.Jeroen Ooms

2 Answers

49
votes

In answer to your second question (If a CORS enabled server sets a session_token through a cookie...?), the cookie is saved under the domain of the CORS server. The main web page's JS code can't access the cookie, even via document.cookie. The cookie is only sent to the server when the .withCredentials property is set, and even then, it is only accepted when the server sets the Access-Control-Allow-Credentials header.

Your first question is a little more open ended. It is fairly secure, but there are ways to circumvent things. For example, an attacker could use a DNS poisoning technique to cause a preflight request to hit the actual server, but send the actual CORS request to the rogue server. Here are some more resources on CORS security:

Lastly, your concern is around giving any website access to your CORS data. In order to protect against this, you should not use the Access-Control-Allow-Origin: * header. Instead, you should echo back the user's Origin value. For example:

Access-Control-Allow-Origin: http://www.example.com

This header will allow only http://www.example.com to access the response data.

26
votes

The intention of CORS is to allow cross-origin requests for XHR requests while giving the server the authority to specify what origin has access to which resource. In particular, CORS introduced the Origin header field that allows the server to tell regular and possible XHR requests apart. This header field cannot be set or changed by the user but is set by the browser for XHR requests.

So if you have an API that is designed to be only used by XHR, you can (and should) require the request to conform with CORS. Especially if the requests can also modify state on your server as otherwise you would be vulnerable to CSRF.

Note the CSRF attacks are possible regardless of CORS using other methods to forge GET and POST requests. CORS does only enable to access the server’s response of XHR requests with JavaScript if the server allows it.