Few questions about CORS and AJAX - javascript

So I wish to make some cross domain AJAX requests and wanted to check a few things.
Is it possible to get CORS to work on IE < 8?
I am required to ensure that the Access-Control-Allow-Origin header is set on the response from the server I am making an AJAX request to. Other than allowing every site to make a request, are there any security risks from setting this to *?
From a client security perspective, by DEFAULT a CORS request does not sent cookies (e.g. session data) to the server I am making the AJAX request to. HOWEVER, it is possible to send cookie data etc...is this statement correct?

Is it possible to get CORS to work on IE < 8?
Unfortunately not. Microsoft's XDomainRequest didn't arrive until IE8.
Other than allowing every site to make a request, are there any security risks from setting Access-Control-Allow-Origin to *?
Strictly speaking no, but this in itself presents a range of potential security issues. Unless you need all origins allowed, configuring a whitelist is preferred.
From a client security perspective, by DEFAULT a CORS request does not send cookies to the server I am making the AJAX request to. HOWEVER, it is possible. Is this statement correct?
Yes, correct. If you want to include cookies, you must configure the XHR's withCredentials property.
Additional information:
MDN Access Control (CORS)

Related

What are the security implications of setting Access-Control-Allow-Headers: *, if any? [duplicate]

I recently had to set Access-Control-Allow-Origin to * in order to be able to make cross-subdomain AJAX calls. I feel like this might be a security problem. What risks am I exposing myself to if I keep the setting?
By responding with Access-Control-Allow-Origin: *, the requested resource allows sharing with every origin. This basically means that any site can send an XHR request to your site and access the server’s response which would not be the case if you hadn’t implemented this CORS response.
So any site can make a request to your site on behalf of their visitors and process its response. If you have something implemented like an authentication or authorization scheme that is based on something that is automatically provided by the browser (cookies, cookie-based sessions, etc.), the requests triggered by the third party sites will use them too.
This indeed poses a security risk, particularly if you allow resource sharing not just for selected resources but for every resource. In this context you should have a look at When is it safe to enable CORS?.
Update (2020-10-07)
Current Fetch Standard omits the credentials when credentials mode is set to include, if Access-Control-Allow-Origin is set to *.
Therefore, if you are using a cookie-based authentication, your credentials will not be sent on the request.
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: *.
AFAIK, Access-Control-Allow-Origin is just a http header sent from the server to the browser. Limiting it to a specific address (or disabling it) does not make your site safer for, for example, robots. If robots want to, they can just ignore the header. The regular browsers out there (Explorer, Chrome, etc.) by default honor the header. But an application like Postman simply ignores it.
The server end doesn't actually check what the 'origin' is of the request when it returns the response. It just adds the http header. It's the browser (the client end) which sent the request that decides to read the access-control header and act upon it. Note that in the case of XHR it may use a special 'OPTIONS' request to ask for the headers first.
So, anyone with creative scripting abilities can easily ignore the whole header, whatever is set in it.
See also Possible security issues of setting Access-Control-Allow-Origin.
Now to actually answer the question
I can't help but feel that I'm putting my environment to security
risks.
If anyone wants to attack you, they can easily bypass the Access-Control-Allow-Origin. But by enabling '*' you do give the attacker a few more 'attack vectors' to play with, like, using regular webbrowsers that honor that HTTP header.
Here are 2 examples posted as comments, when a wildcard is really problematic:
Suppose I log into my bank's website. If I go to another page and then
go back to my bank, I'm still logged in because of a cookie. Other
users on the internet can hit the same URLs at my bank as I do, yet
they won't be able to access my account without the cookie. If
cross-origin requests are allowed, a malicious website can effectively
impersonate the user.
– Brad
Suppose you have a common home router, such as a Linksys WRT54g or
something. Suppose that router allows cross-origin requests. A script
on my web page could make HTTP requests to common router IP addresses
(like 192.168.1.1) and reconfigure your router to allow attacks. It
can even use your router directly as a DDoS node. (Most routers have
test pages which allow for pings or simple HTTP server checks. These
can be abused en masse.)
– Brad
I feel that these comments should have been answers, because they explain the problem with a real life example.
This answer was originally written as a reply to What are the security implications of setting Access-Control-Allow-Headers: *, if any? and was merged despite being irrelevant to this question.
To set it to a wildcard *, means to allow all headers apart from safelisted ones, and remove restrictions that keeps them safe.
These are the restrictions for the 4 safelisted headers to be considered safe:
For Accept-Language and Content-Language: can only have values consisting of 0-9, A-Z, a-z, space or *,-.;=.
For Accept and Content-Type: can't contain a CORS-unsafe request header byte: 0x00-0x1F (except for 0x09 (HT), which is allowed), "():<>?#[\]{}, and 0x7F (DEL).
For Content-Type: needs to have a MIME type of its parsed value (ignoring parameters) of either application/x-www-form-urlencoded, multipart/form-data, or text/plain.
For any header: the value’s length can't be greater than 128.
For simplicity's sake, I'll base my answer on these headers.
Depending on server implementation, simply removing these limitations can be very dangerous (to the user).
For example, this outdated wordpress plugin has a reflected XSS vulnerability where the value of Accept-Language was parsed and rendered on the page as-is, causing script execution on the user's browser should a malicious payload be included in the value.
With the wildcard header Access-Control-Allow-Headers: *, a third party site redirecting to your site could set the value of the header to Accept Language: <script src="https://example.com/malicious-script.js"></script>, given that the wildcard removes the restriction in Point 1 above.
The preflight response would then give the greenlight to this request, and the user will be redirected to your site, triggering an XSS on their browser, which impact can range from an annoying popup to losing control of their account through cookie hijacking.
Thus, I would strongly recommend against setting a wildcard unless it is for an API endpoint where nothing is being rendered on the page.
You can set Access-Control-Allow-Headers: Pragma as an alternative solution to your problem.
Note that the value * only counts as a special wildcard value for requests without credentials (requests without HTTP cookies or HTTP authentication information), otherwise it will be read as a literal header. Documentation
In scenario where server attempts to disable the CORS completely by setting below headers.
Access-Control-Allow-Origin: * (tells the browser that server accepts
cross site requests from any ORIGIN)
Access-Control-Allow-Credentials: true (tells the browser that cross
site requests can send cookies)
There is a fail safe implemented in browsers that will result in below error
"Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’"
So in most scenarios setting ‘Access-Control-Allow-Origin’ to * will not be a problem. However to secure against attacks, the server can maintain a list of allowed origins and whenever server gets a cross origin request, it can validate the ORIGIN header against the list of allowed origins and then echo back the same in Access-Control-Allow-Origin header.
Since ORIGIN header can't be changed by javascript running on the browser, the malicious site will not be able to spoof it.

Does Cross-origin resource sharing affect all clients that connect to a web method?

I have a web method that I want to call from my C# app and was provided with a Javascript example, showing how to call the method. I have established that running the Javascript from my desktop runs into CORS problems - i was able to run the sample when I put the javascript on the server and ran it from the same folder as the web method.
Will my C# app run into the same CORS issue? or will it be ok because only the browsers have the built in CORS security?
--Edit--
I've been using System.Net.Http.HttpClient and http://restsharp.org/
Am I correct in assuming that these two objects are wrappers around a web browser? and that they will have issues with CORS?
I really don't want to have to write Sockets code.
Due to security reasons browsers restrict cross-origin HTTP requests initiated from within scripts on the browser. For example, XMLHttpRequest follows the same-origin policy. That means a web application using XMLHttpRequest could only make HTTP requests to its own domain. This prevents application from being vulnerable to CSRF attacks. However, there are cases when applications need to access resources from different domain. This is when CORS comes into play to allow cross-domain requests.
Having said all that, your C# app should be able to call the WEB API without any CORS issues as long as it's a socket to socket communication (not via browser).
Some where in deep recess of my mind I remember browser related cors will always be blocked unless noted or changed like for example if you're in chrome and have the cors extension allow browser cors control, but on the server side, their is nothing preventing servers from interacting with one another.
but it depends on what is allowed on the headers
I'll try to produce some documentation that confirms that.
https://spring.io/understanding/CORS
The request includes an Origin header that indicates the origin of the client code.
The server will consider the request's Origin and either allow or disallow the request. If the server allows the request, then it will respond with the requested resource and an Access-Control-Allow-Origin header in the response. This header will indicate to the client which client origins will be allowed to access the resource. Assuming that the Access-Control-Allow-Origin header matches the request's Origin, the browser will allow the request.
On the other hand, if Access-Control-Allow-Origin is missing in the response or if it doesn't match the request's Origin, the browser will disallow the request.

is it possible to ignore ajax cookies via javascript

Is there a programmatic way in javascript to ignore cookies sent from the server (without changing browser settings).
We use certain plugins on our web server that will randomly update our security cookie. However this causes issues for some of our URLs and we want to ignore those cookies for some cases.
Our security architect recommended we look into this possibility.
example:
1). create ajax request with URL: www.site.com/abc/comtd
2). ignore any cookies that come back in the response
The only way I can think of is to send the AJAX request from a completely different domain. Because the AJAX would be a Cross-Origin Resource Sharing (CORS) request, any response headers would be denied unless the server sends the access-control-allow-origin header. If the AJAX request is not a CORS request, the browser has to respect all Set-cookie headers it receives per the standard.
its not an option in our case to change domains. We need to pass cookies to the server or the requests will not get through security. If we change domains our security cookies would not get passed. What we want is to pass the cookies but ignore any set-cookie response headers for certain URLs.
I think this is not possible on the browser so I am investigating some Apache server plugins like mod_headers. Maybe we can do it on the server itself. Im closing this question and will open another one related to mod_headers.
Just a thought - if you send the request from a WebWorker - I think that is isolated from the main browser context ?

Security implications of adding all domains to CORS (Access-Control-Allow-Origin: *)

It is said that instead of adding all domains to CORS, one should only add a set of domains.
Yet it is sometimes not trivial to add a set of domains. E.g. if I want to publicly expose an API then for every domain that wants to make a call to that API I would need to be contacted to add that domain to the list of allowed domains.
I'd like to make a conscious trade off decision between security implications and less work.
The only security issues I see are DoS attacks and CSRF attacks.
CSRF attacks can already be achieved with IMG elements and FORM elements.
DoS attacks related to CORS can be overcome by blocking requests upon the referrer header.
Am I missing security implications?
===Edit===
It is assumed that the Access-Control-Allow-Credentials Header is not set
I know how to add a given list of domains "CORS access" and I'm therefore only interested in the security implications of adding all domains "CORS access"
Cross-Site Request Forgery attacks are far and away the primary concern that Access-Control-Allow-Origin addresses.
Ryan is certainly correct regarding content retrieval. However, on the subject of making the request there is more to say here. Many web sites now provide RESTful web services that expose a wide range of features that may involve making significant changes in the backend. Very often, these RESTful services are intended to be invoked with an XHR (e.g. AJAX) request (probably with a "Single Page Application" as the front-end). If a user has an active session granting access to these services when they visit a malicious third-party site, that site may try to invoke those REST endpoints behind the scenes, passing in values that could compromise the user or the site. Depending on how the REST services are defined, there are various ways to protect against this.
In the specific case of REST web services for a Single Page App, you can dictate that all requests to the backend REST endpoints are made with XHR and refuse any non-XHR request. You can dictate this by checking for the presence of a custom request header (something like jQuery's X-Requested-With). Only XHR-type requests can set these headers; simple GET and POST requests from forms and embedded resources cannot. Finally, the reason that we want to dictate XHR requests gets us back to the original question - XHR requests are subject to CORS rules.
If you allowed Access-Control-Allow-Origin: *, then any site could make any AJAX request on the user's behalf to your REST endpoints. If your REST endpoints involve any kind of sensitive data or allow for data persistence, then this is an unacceptable security vulnerability. Instead, enforce XHR-only requests like I described and define a whitelist of origins allowed to make those requests.
It's worth pointing out that if your REST endpoints do not expose any sensitive information, or if they don't allow the user to make any persistent data changes, then Access-Control-Allow-Origin: * may be the appropriate decision. Google Maps for instance provides read-only views into public map data; there is no reason to restrict the third party sites that may wish to invoke those services.
Old question, but a lot of bad answers here so I have to add mine.
If you don't set Access-Control-Allow-Credentials, and you do cookie-less authentication (ie the caller supplies a Bearer Authorization header) then you don't need to whitelist origins. Just echo the origin back in Access-Control-Allow-Origin.
A well-structured REST API can be called safely from any origin.
You can send more than one, like:
Access-Control-Allow-Origin: http://my.domain.com https://my.domain.com http://my.otherdomain.com
but I would advise against it. Instead, keep a whitelist of allowed domains. Lets say:
allowed = [ "X", "Y", "A.Z" ];
Then if you get a request from X you respond with:
Access-Control-Allow-Origin: X
If you get a request from A.Z you respond with:
Access-Control-Allow-Origin: A.Z
If you get a request from a domain that is not allowed, respond with an error or no CORS policy.
All XHR requests will send an Origin header, so use that. And you only need to send the CORS policy headers for the OPTIONS request, not the GET/POST/HEAD request that follows.
The main issue I see is that you expose all your domains. Maybe you have a secure admin domain like: https://admin.mydomain.com, or maybe you have a product website that isn't ready for launch yet. You don't want to include anything that isn't absolutely necessary for the request at hand.
And * is just extremely lazy.
CORS is about getting content back, not just making the request. When you get a resource through an img or script tag, you can trick someone's browser into making a CSRF style request. This is normal, and you can protect against that with a normal CSRF token.
With CORS enabled on all domains, you can now have javascript on an attacking site make a request and get back the content, invading their privacy.
Example:
Imagine your back enables CORS for all domains. Now I make a website that makes a request to yourimaginarybank.com/balance
An IMG request would do nothing, because my javascript can't get what was in the html of that page on your bank's website. Now that they have turned on CORS, the javascript on my site actually gets back an HTML page with your balance on it, and saves it to my server. Not only can I make a GET request like before, but now I can see what is inside. This is a huge security problem.
How to solve the problem without adding a big list into your headers? Each CORS request is made with the Origin header. The best solution is probably to read the Origin header then query a database to see if it is whitelisted as suggested by Fritz in his answer.
Except of csauve's one, none of the replies answer my original question.
To answer my question; It seems that as long as Access-Control-Allow-Credentials is not set then there is no security problem.
(Which makes me wonder why the spec requires preflight when Access-Control-Allow-Credentials is not set?)
Best Practice is to first check the domain of the incoming request and then generate the response header. Depending on whether this domain is allowed to send requests, you add it (just this one) to the Access-Control-Allow-Origin response header.
Afaik, it is not even possible to add more than one domain to this header. So it's either * or one specific domain and I would always prefer not to add *

Javascript HTTP GET and POST

When initiating a HTTP GET or POST request:
Common browsers do not allow Javacript to call cross domain
So it means that every HTTP request from a given domain the "Host" in the Request header represents the origin host, say foo.com and that it cannot be modified by the client request?
Furthermore, when a request originated from a subdomain, like bar.foo.com then the "Host" in the request header will be "bar.foo.com"
And that this holds true when doing Cross-domain HTTP request, i.e. the "Host" will be foo.com or if from subdomain bar.foo.com, and that the receiving end (the other domain) will see the "Host" as these hosts respectively?
Everything through the HTTP browser sandbox (not just AJAX calls! IFRAMEs have restrictions based on the same conditions, for different things - namely, you can't control the content of an IFRAME on another domain/host/port/proto, just load pages and see the URI of what is loaded. Content in JS is off-limits) is done client-side rather than server-side: your browser will actively refuse to query anything that does not have:
The same hostname (subdomains count as different hostnames)
The same port
The same access method (HTTP or HTTPS)
For AJAX, this leads into a big red "cannot get due to security"-esque error. For some browsers, the request does happen: there is a way to bypass this restriction, using access-control headers. These effectively tell your browser "I'm friendly to x", where x is a wildcard list of domains (and where * means everything).
To figure this one out, browsers will perform the request, and if CORS is not on, will actively fire an exception (XMLHttpRequest: x is not allowed by y). The request, however, has happened.
The obvious solution is to add an Access-Control-Allow-Origin header in order to signify that cross-domain queries to this site are okay. However, bear in mind two things:
Most browsers have it, but some don't (IE8 <.<)
CORS has some little bugs of its own if the URLs are hardcoded in the script (read up on it!)
You'll therefore want a JSONP fallback for IE. However, keep in mind that all this is done client-side and is no guarantee that there aren't any browsers that will actively disregard CORS or the webkit security model. The entire model also relies on client-side Host resolution.
If the question is "Is this true", then then the answer is no.
Browsers do allow JavaScript to create GET and POST requests cross domain. What they don't allow is javascript to read the response from a cross domain request.
The 'Host' in the HTTP header represents the host that the request is being sent to, not the website that caused the host. HOST is necessary because servers are often shared and one server may host many separate websites, so they need to know which one is being requested.
The website that created the website is often (although not always) identified in the 'REFERER' HTTP Header.
A server that supports CORS will inspect the Origin header in the request. The value will be as you described, the server that the request orignates from. In it's reply, the server will send a header called Access-Control-Allow-Origin. If this matches Origin, the browser will accept the response. It obviously also require the browser to support CORS.
Wikipedia have a fairly good explanation of how it works.
The Host HTTP request header is always the domain that the request is going to.
If you're initiating an HTTP GET or POST request using the XMLHTTPRequest method, then it won't let you send the request if the JavaScript code that sends it isn't on the same domain as the URL you're sending a request too - unless the browser supports cross-origin resource sharing.
If the browser does support cross-origin resource sharing (CORS), then it will send your request to other domains, but with an additional Origin header, indicating the site that served the JavaScript making the request. If the server allows the request, it'll respond with an Access-Control-Allow-Origin header, listing the domains it'll accept requests from.

Categories

Resources