Understanding Ajax Cors and Security Considerations

Understanding AJAX CORS and security considerations

As I learned from this post, when page from www.a.com makes AJAX request to www.b.com, then it's the www.b.com that decides if request should be allowed or not.

Not quite. The request isn't blocked (at least, if it is simple).

By default the JavaScript running on www.a.com is forbidden access to the response from www.b.com.

CORS provides a means by which www.b.com can give permission to the JavaScript on www.a.com to access the response.

But what is exactly secured on client in such model?

It stops the author of www.a.com from reading data from www.b.com using the browser of a User who has visited both sites and has been authenticated on www.b.com (and thus has access to data that isn't public).

For example, Alice is logged into Google. Alice visits malicious.example which uses XMLHttpRequest to access data from gmail.com. Alice has a GMail account so the response has a list of the most recent email in her inbox. The same origin policy prevents malicious.example from reading it.

For example, hacker success to make XSS script injection to my page, then it makes AJAX request to his domain to store user data. So hackers domain will allow such request for sure.

Correct. XSS is a different security problem that needs to be addressed at source (i.e. at www.a.com and not in the browser).

Understanding CORS security: what's the use of server allowing browser cross-domain access?

I have never heard of a server trying to restrict access from alien webpages.

The Same Origin Policy is a restriction imposed by browsers, not servers.

CORS is the server telling the browser that it can relax its normal security because the data doesn't need that level of protection.


Even if server wanted to restrict connections from other domains, it's impossible to do this using capabilities of HTTP protocol.

Which is why HTTP the protocol isn't used for that.

I suggest using tokens for that.

Using a nonce to protect against CSRF solves a different problem.

It's a relatively expensive solution that you only need to get out when it is the side effects of the request that can be problematic (e.g. "Post a new comment") rather then the data being passed back to JavaScript running on another site.

You couldn't use them instead of the Same Origin Policy to protect against reading data across origins because (without the Same Origin Policy) the attacking site would be able to read the token.


What's the use of blocking XMLHttpRequests while you still can use jsonp?

You can't use JSONP unless the server provides the data in JSONP.

Providing the data in JSONP and using CORS to grant permission to access resources are two different ways that the server can allow the browser to access data that is normally protected by the Same Origin Policy.

JSONP was a hack. CORS came later and is more flexible (since it can allow access to any kind of data, respond to request methods other than GET, and allow custom HTTP headers to be added).


Can you explain why is this done that way?

The default policy is "No Access" since there is no way for the browser to know if the data being requested is public or not.

Consider this situation:

Alice has an account on Bob's website. That account is password protected and has information that should be kept secret between Alice and Bob (bank records or exam results, for example).

Mallory has another website. It uses Ajax to try to access Bob's site.

Without the Same Origin Policy, Alice might (while logged in to Bob's site) visit Mallory's website. Without Alice's knowledge or permission, Mallory's website sends JavaScript to Alice's browser that uses Ajax to fetch data from Bob's site. Since it is coming from Alice's browser, all of Alice's private information is given to the JavaScript. The JavaScript then sends it to Mallory.

This is clearly not a good thing.

The Same Origin Policy prevents that.

If Bob, as the person running the site, decides that the information is not secret and can be shared publicly, then he can use CORS or JSONP to provide access to it to JavaScript running on other sites.


Do you know a way to prevent any cross-domain request from a webpage.

No. The webpage is a single entity. Trying to police parts of it from other parts is a fool's errand.

Imagine a junior web developer creating a login form on a page having ads or other scripts potentially sniffing passwords? Isn't this the essence of web security? Why anyone is talking about that?

"Be careful about trusting third party scripts" is something that doesn't get mentioned as much as it should be. Thankfully, most ad providers and CDN hosted libraries are supplied by reasonably trustworthy people.


Do you know an easy way of overcoming the problem of missing Access-Control-Allow-Origin

  • Configure the server so it isn't missing.
  • Use JSONP instead
  • Use a proxy that isn't blocked by the same origin policy to fetch the data instead (you won't get any credentials the browser might send because Alice has an account with Bob though).

What security risks exist when setting Access-Control-Allow-Origin to accept all domains?

Access-Control-Allow-Origin: * is totally safe to add to any resource, unless that resource contains private data protected by something other than standard credentials. Standard credentials are cookies, HTTP basic auth, and TLS client certificates.

Eg: Data protected by cookies is safe

Imagine https://example.com/users-private-data, which may expose private data depending on the user's logged in state. This state uses a session cookie. It's safe to add Access-Control-Allow-Origin: * to this resource, as this header only allows access to the response if the request is made without cookies, and cookies are required to get the private data. As a result, no private data is leaked.

Eg: Data protected by location / ip / internal network is not safe (unfortunately common with intranets and home appliances):

Imagine https://intranet.example.com/company-private-data, which exposes private company data, but this can only be accessed if you're on the company's wifi network. It's not safe to add Access-Control-Allow-Origin: * to this resource, as it's protected using something other than standard credentials. Otherwise, a bad script could use you as a tunnel to the intranet.

Rule of thumb

Imagine what a user would see if they accessed the resource in an incognito window. If you're happy with everyone seeing this content (including the source code the browser received), it's safe to add Access-Control-Allow-Origin: *.

Security concerns about CORS

Now my main concern is, can't the HTTP headers be spoofed? For example, can't an attacker curl a request to the other server, sending the exact HTTP headers that my CORS request does?

You have two misconceptions here.

  1. CORS headers are sent by the server not the client (although sometimes a client will make a pre-flight OPTIONS request)
  2. What the Same Origin Policy is defending against

The Same Origin Policy exists to stop Mallory's (evil) website from getting data from Bob's website by asking Alice's browser to request it when Alice visits Mallory's website.

If that was possible, then Mallory could get any information that was supposed to be a shared secret between Alice and Bob (such as Alice's account balance on Bob's banking website).

can't an attacker curl a request to the other server, sending the exact HTTP headers that my CORS request does?

Since Mallory has no way of knowing what security credentials need to be included in the request (because, for instance, they are stored in Alice's cookies for Bob's website): No.

But CORS doesn't matter here, but the Same Origin Policy isn't implemented by cURL since it isn't a browser running JavaScript supplied by arbitrary websites.

I guess sensitive information should never be shared within a CORS communication

It depends on the nature of the information.

If Alice and whatever websites you authorise in the CORS headers are allowed to see it, then it is fine to send it (although you should probably use SSL): So long as you have authenticated Alice's identity.

If only Alice and you site should see it, then don't put CORS headers on it (and don't provide any other way to bypass the Same Origin Policy, such as JSON-P).

If Alice shouldn't see it, then you should never send it to Alice's browser, CORS or no CORS.

Why the cross-domain Ajax is a security concern?

Why are Ajax HTTP Requests not allowed to cross domain boundaries.

Because AJAX requests are (a) submitted with user credentials, and (b) allow the caller to read the returned data.

It is a combination of these factors that can result in a vulnerability. There are proposals to add a form of cross-domain AJAX that omits user credentials.

you could simply add an img, script, or iframe element to the document

None of those methods allow the caller to read the returned data.

(Except scripts where either it's deliberately set up to allow that, for permitted cross-domain scripting - or where someone's made a terrible cock-up.)

Your can do XSS attacks without using this at all. Posting to third party site

That's not an XSS attack. That's a cross-site request forgery attack (XSRF). There are known ways to solve XSRF attacks, such as including one-time or cryptographic tokens to verify that the submission came deliberately from the user and was not launched from attacker code.

If you allowed cross-domain AJAX you would lose this safeguard. The attacking code could request a page from the banking site, read any authorisation tokens on it, and submit them in a second AJAX request to perform the transfer. And that would be a cross-site scripting attack.

How to get a cross-origin resource sharing (CORS) post request working

I finally stumbled upon this link "A CORS POST request works from plain javascript, but why not with jQuery?" that notes that jQuery 1.5.1 adds the

 Access-Control-Request-Headers: x-requested-with

header to all CORS requests. jQuery 1.5.2 does not do this. Also, according to the same question, setting a server response header of

Access-Control-Allow-Headers: *

does not allow the response to continue. You need to ensure the response header specifically includes the required headers. ie:

Access-Control-Allow-Headers: x-requested-with 

Possible security issues of setting Access-Control-Allow-Origin

CORS headers are typically used for JavaScript AJAX request. Browsers have a built-in safety mechanism that doesn't allow you to query other domains unless they explicitly allow it by setting these CORS headers.

There isn't much of a security risk really. You can always send malicious requests anyway. Browsers just collectively decide to play nice.

One thing to be aware of is that you don't necessarily always want to send the

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

header. This could potentially lead people to all the domains that make use of your API. My recommendation is that you only emit the header if it is necessary, ie. you get an OPTIONS request from a whitelisted domain.

I wrote a blog post about this recently: http://fritsvancampen.wordpress.com/2013/02/03/cross-site-origin-requests-aka-cross-origin-resource-sharing/



Related Topics



Leave a reply



Submit