What is the real meaning of SOP (Same Origin Policy)?
I know it means that the Javascript code from one origin cannot accuess resources from another origin. But what exactly does the word "resources" mean? For example:
Javascript code can access IMAGES from another site.
Javascript code cannot make ajax request to another side.
But when you use JSON padding, after completing the loading of a padded script tag, the 3rd party script will call your specified callback -- Javascript code from one site is invoking a method of Javascript code from another. Does this violate SOP?
There are several types but if we don't specify:
SOP refers to a mechanism that governs the ability for JavaScript and other scripting languages to access DOM properties and methods across domains
Here you have an excellent description of different types of SOP.
Same Origin Policy is mainly intended to prevent scripts for other domains to perform AJAX (XMLHTTP) requests in the context of the loaded domain and also restricts sites of other domain to access sites resources like cookies, local storage etc. It is more like a standard specification formulated for security measures and every browser has its own way of implementing it by adhering to specifications.
By saying 'prevent scripts for other domains to perform AJAX (XMLHTTP) requests' I mean the cross-origin requests which don't belong to the same domain.
For example, domain.com and test.domain.com belong to the same domain and the test is subdomain, while test.domain2.com belongs to an entirely different domain.
Now let us consider its security implications:-
1.Let us say a website site1.com has an API call to update the password. When the user inputs the required data an HTTP call is made to the backend and the user's authenticity is validated with the session data contained in cookies.
2)Now with this being said, if the attacker creates a site named site2 and has a javascript code to make an HTTP call to site1's change password endpoint. By browsers default behavior it attaches all the cookie data it has for site1 to the request which makes the HTTP call successful thus allowing attackers to succeed.
3)To be able to mitigate this browsers implemented SOP, which dictates the browsers javascript engine to block any request to cross domains like from site2 to site1 for example, unless instructed to allow to do so.
4)Now in this growing modern world with microservice architectures and multiple subdomains, this will be very problematic. To get around this browsers support cross-origin requests if the API response says so with headers like Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Credentials, etc.
5)To put it forward when the ajax request is made from site2 to site1, the browsers check the API response headers and allows the request if any of these values are present in response:-
Access-Control-Allow-Origin:* or Access-Control-Allow-Origin:site2.com or Access-Control-Allow-Origin:*.site2.com (wildcard entry)
6)With this being said there is a major loophole here, even if the sop policy blocks the request, it actually means that the browser blocks the site2 access to read the response data meaning the request was already made to the server. This scenario is only applicable to a few requests on specific conditions which doesn't trigger pre-flight options call. When the options call is made the browser will not allow the request to go through based on the header response in options call.
7)Now comes the second part to it which is Access-Control-Allow-Credentials. In the server response for options call, if the server sets the header to true all the confidential session data like Authorization header, secure cookies will be added to the cross-origin requests from site2 to site1.
Note:- This header is only added if Access-Control-Allow-Origin is very specific to a domain meaning it will not work for * value in the header. Is the Access-Control-Allow-Origin header is * then browsers SOP policy will kick in and blocks it from allowing the secure data if Access-Control-Allow-Credentials is set to true.
The SOP origin policy doesn't deal with image sources and external script includes. To be able to utilize control over those go through the Content Security Policy (CSP). Using it you could control access to external sites wrt to images, scripts, fonts, styles, etc. You would also be able to block unsafe-inline eval's in site like alert boxes to prevent some XSS attacks. This is new defacto standard and a lot of websites started implementing it.
To be able to prevent such attacks (CSRF attacks), websites also implement a csrf-token along with a form that changes on every state change. Even if attacker somehow makes the request from site2 to site1, the request will not go through as the server at site1 validates the csrf token along with the request, which the attacker cannot access through.
Other measures would add origin-based validation if the origin header is present.
JSONP is designed to allow such a mechanism through callbacks.
Sorry for such a long answer and the topic is far bigger than this. This is just my own understanding of it and let me know if I am wrong anywhere.
JSONP gets around the Same Origin Policy by dynamically adding a script tag to the DOM and calling a predefined function with the remote web service's JSON data as the parameter. The tag is not subject to the same origin policy and therefore can request content cross-domain.
Just like how you can use Google's version of jQuery on your site without violating SOP, you can "include" a script tag that calls a predefined function on the data you receive back from a web service.
Related
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.
tl;dr; About the Same Origin Policy
I have a Grunt process which initiates an instance of express.js server. This was working absolutely fine up until just now when it started serving a blank page with the following appearing in the error log in the developer's console in Chrome (latest version):
XMLHttpRequest cannot load https://www.example.com/
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:4300' is therefore not allowed access.
What is stopping me from accessing the page?
tl;dr — When you want to read data, (mostly) using client-side JS, from a different server you need the server with the data to grant explicit permission to the code that wants the data.
There's a summary at the end and headings in the answer to make it easier to find the relevant parts. Reading everything is recommended though as it provides useful background for understanding the why that makes seeing how the how applies in different circumstances easier.
About the Same Origin Policy
This is the Same Origin Policy. It is a security feature implemented by browsers.
Your particular case is showing how it is implemented for XMLHttpRequest (and you'll get identical results if you were to use fetch), but it also applies to other things (such as images loaded onto a <canvas> or documents loaded into an <iframe>), just with slightly different implementations.
The standard scenario that demonstrates the need for the SOP can be demonstrated with three characters:
Alice is a person with a web browser
Bob runs a website (https://www.example.com/ in your example)
Mallory runs a website (http://localhost:4300 in your example)
Alice is logged into Bob's site and has some confidential data there. Perhaps it is a company intranet (accessible only to browsers on the LAN), or her online banking (accessible only with a cookie you get after entering a username and password).
Alice visits Mallory's website which has some JavaScript that causes Alice's browser to make an HTTP request to Bob's website (from her IP address with her cookies, etc). This could be as simple as using XMLHttpRequest and reading the responseText.
The browser's Same Origin Policy prevents that JavaScript from reading the data returned by Bob's website (which Bob and Alice don't want Mallory to access). (Note that you can, for example, display an image using an <img> element across origins because the content of the image is not exposed to JavaScript (or Mallory) … unless you throw canvas into the mix in which case you will generate a same-origin violation error).
Why the Same Origin Policy applies when you don't think it should
For any given URL it is possible that the SOP is not needed. A couple of common scenarios where this is the case are:
Alice, Bob, and Mallory are the same person.
Bob is providing entirely public information
… but the browser has no way of knowing if either of the above is true, so trust is not automatic and the SOP is applied. Permission has to be granted explicitly before the browser will give the data it has received from Bob to some other website.
Why the Same Origin Policy applies to JavaScript in a web page but little else
Outside the web page
Browser extensions*, the Network tab in browser developer tools, and applications like Postman are installed software. They aren't passing data from one website to the JavaScript belonging to a different website just because you visited that different website. Installing software usually takes a more conscious choice.
There isn't a third party (Mallory) who is considered a risk.
* Browser extensions do need to be written carefully to avoid cross-origin issues. See the Chrome documentation for example.
Inside the webpage
Most of the time, there isn't a great deal of information leakage when just showing something on a webpage.
If you use an <img> element to load an image, then it gets shown on the page, but very little information is exposed to Mallory. JavaScript can't read the image (unless you use a crossOrigin attribute to explicitly enable request permission with CORS) and then copy it to her server.
That said, some information does leak so, to quote Domenic Denicola (of Google):
The web's fundamental security model is the same origin policy. We
have several legacy exceptions to that rule from before that security
model was in place, with script tags being one of the most egregious
and most dangerous. (See the various "JSONP" attacks.)
Many years ago, perhaps with the introduction of XHR or web fonts (I
can't recall precisely), we drew a line in the sand, and said no new
web platform features would break the same origin policy. The existing
features need to be grandfathered in and subject to carefully-honed
and oft-exploited exceptions, for the sake of not breaking the web,
but we certainly can't add any more holes to our security policy.
This is why you need CORS permission to load fonts across origins.
Why you can display data on the page without reading it with JS
There are a number of circumstances where Mallory's site can cause a browser to fetch data from a third party and display it (e.g. by adding an <img> element to display an image). It isn't possible for Mallory's JavaScript to read the data in that resource though, only Alice's browser and Bob's server can do that, so it is still secure.
CORS
The Access-Control-Allow-Origin HTTP response header referred to in the error message is part of the CORS standard which allows Bob to explicitly grant permission to Mallory's site to access the data via Alice's browser.
A basic implementation would just include:
Access-Control-Allow-Origin: *
… in the response headers to permit any website to read the data.
Access-Control-Allow-Origin: http://example.com
… would allow only a specific site to access it, and Bob can dynamically generate that based on the Origin request header to permit multiple, but not all, sites to access it.
The specifics of how Bob sets that response header depend on Bob's HTTP server and/or server-side programming language. Users of Node.js/Express.js should use the well-documented CORS middleware. Users of other platforms should take a look at this collection of guides for various common configurations that might help.
NB: Some requests are complex and send a preflight OPTIONS request that the server will have to respond to before the browser will send the GET/POST/PUT/Whatever request that the JS wants to make. Implementations of CORS that only add Access-Control-Allow-Origin to specific URLs often get tripped up by this.
Obviously granting permission via CORS is something Bob would only do only if either:
The data was not private or
Mallory was trusted
How do I add these headers?
It depends on your server-side environment.
If you can, use a library designed to handle CORS as they will present you with simple options instead of having to deal with everything manually.
Enable-Cors.org has a list of documentation for specific platforms and frameworks that you might find useful.
But I'm not Bob!
There is no standard mechanism for Mallory to add this header because it has to come from Bob's website, which she does not control.
If Bob is running a public API then there might be a mechanism to turn on CORS (perhaps by formatting the request in a certain way, or a config option after logging into a Developer Portal site for Bob's site). This will have to be a mechanism implemented by Bob though. Mallory could read the documentation on Bob's site to see if something is available, or she could talk to Bob and ask him to implement CORS.
Error messages which mention "Response for preflight"
Some cross-origin requests are preflighted.
This happens when (roughly speaking) you try to make a cross-origin request that:
Includes credentials like cookies
Couldn't be generated with a regular HTML form (e.g. has custom headers or a Content-Type that you couldn't use in a form's enctype).
If you are correctly doing something that needs a preflight
In these cases then the rest of this answer still applies but you also need to make sure that the server can listen for the preflight request (which will be OPTIONS (and not GET, POST, or whatever you were trying to send) and respond to it with the right Access-Control-Allow-Origin header but also Access-Control-Allow-Methods and Access-Control-Allow-Headers to allow your specific HTTP methods or headers.
If you are triggering a preflight by mistake
Sometimes people make mistakes when trying to construct Ajax requests, and sometimes these trigger the need for a preflight. If the API is designed to allow cross-origin requests but doesn't require anything that would need a preflight, then this can break access.
Common mistakes that trigger this include:
trying to put Access-Control-Allow-Origin and other CORS response headers on the request. These don't belong on the request, don't do anything helpful (what would be the point of a permissions system where you could grant yourself permission?), and must appear only on the response.
trying to put a Content-Type: application/json header on a GET request that has no request body the content of which to describe (typically when the author confuses Content-Type and Accept).
In either of these cases, removing the extra request header will often be enough to avoid the need for a preflight (which will solve the problem when communicating with APIs that support simple requests but not preflighted requests).
Opaque responses (no-cors mode)
Sometimes you need to make an HTTP request, but you don't need to read the response. e.g. if you are posting a log message to the server for recording.
If you are using the fetch API (rather than XMLHttpRequest), then you can configure it to not try to use CORS.
Note that this won't let you do anything that you require CORS to do. You will not be able to read the response. You will not be able to make a request that requires a preflight.
It will let you make a simple request, not see the response, and not fill the Developer Console with error messages.
How to do it is explained by the Chrome error message given when you make a request using fetch and don't get permission to view the response with CORS:
Access to fetch at 'https://example.com/' from origin 'https://example.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
Thus:
fetch("http://example.com", { mode: "no-cors" });
Alternatives to CORS
JSONP
Bob could also provide the data using a hack like JSONP which is how people did cross-origin Ajax before CORS came along.
It works by presenting the data in the form of a JavaScript program that injects the data into Mallory's page.
It requires that Mallory trust Bob not to provide malicious code.
Note the common theme: The site providing the data has to tell the browser that it is OK for a third-party site to access the data it is sending to the browser.
Since JSONP works by appending a <script> element to load the data in the form of a JavaScript program that calls a function already in the page, attempting to use the JSONP technique on a URL that returns JSON will fail — typically with a CORB error — because JSON is not JavaScript.
Move the two resources to a single Origin
If the HTML document the JS runs in and the URL being requested are on the same origin (sharing the same scheme, hostname, and port) then the Same Origin Policy grants permission by default. CORS is not needed.
A Proxy
Mallory could use server-side code to fetch the data (which she could then pass from her server to Alice's browser through HTTP as usual).
It will either:
add CORS headers
convert the response to JSONP
exist on the same origin as the HTML document
That server-side code could be written & hosted by a third party (such as CORS Anywhere). Note the privacy implications of this: The third party can monitor who proxies what across their servers.
Bob wouldn't need to grant any permissions for that to happen.
There are no security implications here since that is just between Mallory and Bob. There is no way for Bob to think that Mallory is Alice and to provide Mallory with data that should be kept confidential between Alice and Bob.
Consequently, Mallory can only use this technique to read public data.
Do note, however, that taking content from someone else's website and displaying it on your own might be a violation of copyright and open you up to legal action.
Writing something other than a web app
As noted in the section "Why the Same Origin Policy only applies to JavaScript in a web page", you can avoid the SOP by not writing JavaScript in a webpage.
That doesn't mean you can't continue to use JavaScript and HTML, but you could distribute it using some other mechanism, such as Node-WebKit or PhoneGap.
Browser extensions
It is possible for a browser extension to inject the CORS headers in the response before the Same Origin Policy is applied.
These can be useful for development but are not practical for a production site (asking every user of your site to install a browser extension that disables a security feature of their browser is unreasonable).
They also tend to work only with simple requests (failing when handling preflight OPTIONS requests).
Having a proper development environment with a local development server
is usually a better approach.
Other security risks
Note that SOP / CORS do not mitigate XSS, CSRF, or SQL Injection attacks which need to be handled independently.
Summary
There is nothing you can do in your client-side code that will enable CORS access to someone else's server.
If you control the server the request is being made to: Add CORS permissions to it.
If you are friendly with the person who controls it: Get them to add CORS permissions to it.
If it is a public service:
Read their API documentation to see what they say about accessing it with client-side JavaScript:
They might tell you to use specific URLs
They might support JSONP
They might not support cross-origin access from client-side code at all (this might be a deliberate decision on security grounds, especially if you have to pass a personalized API Key in each request).
Make sure you aren't triggering a preflight request you don't need. The API might grant permission for simple requests but not preflighted requests.
If none of the above apply: Get the browser to talk to your server instead, and then have your server fetch the data from the other server and pass it on. (There are also third-party hosted services that attach CORS headers to publically accessible resources that you could use).
Target server must allowed cross-origin request. In order to allow it through express, simply handle http options request :
app.options('/url...', function(req, res, next){
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'POST');
res.header("Access-Control-Allow-Headers", "accept, content-type");
res.header("Access-Control-Max-Age", "1728000");
return res.sendStatus(200);
});
As this isn't mentioned in the accepted answer.
This is not the case for this exact question, but might help others that search for that problem
This is something you can do in your client-code to prevent CORS errors in some cases.
You can make use of Simple Requests.
In order to perform a 'Simple Requests' the request needs to meet several conditions. E.g. only allowing POST, GET and HEAD method, as well as only allowing some given Headers (you can find all conditions here).
If your client code does not explicit set affected Headers (e.g. "Accept") with a fix value in the request it might occur that some clients do set these Headers automatically with some "non-standard" values causing the server to not accept it as Simple Request - which will give you a CORS error.
This is happening because of the CORS error. CORS stands for Cross Origin Resource Sharing. In simple words, this error occurs when we try to access a domain/resource from another domain.
Read More about it here: CORS error with jquery
To fix this, if you have access to the other domain, you will have to allow Access-Control-Allow-Origin in the server. This can be added in the headers. You can enable this for all the requests/domains or a specific domain.
How to get a cross-origin resource sharing (CORS) post request working
These links may help
This CORS issue wasn't further elaborated (for other causes).
I'm having this issue currently under different reason.
My front end is returning 'Access-Control-Allow-Origin' header error as well.
Just that I've pointed the wrong URL so this header wasn't reflected properly (in which i kept presume it did). localhost (front end) -> call to non secured http (supposed to be https), make sure the API end point from front end is pointing to the correct protocol.
I got the same error in Chrome console.
My problem was, I was trying to go to the site using http:// instead of https://. So there was nothing to fix, just had to go to the same site using https.
This bug cost me 2 days. I checked my Server log, the Preflight Option request/response between browser Chrome/Edge and Server was ok. The main reason is that GET/POST/PUT/DELETE server response for XHTMLRequest must also have the following header:
access-control-allow-origin: origin
"origin" is in the request header (Browser will add it to request for you). for example:
Origin: http://localhost:4221
you can add response header like the following to accept for all:
access-control-allow-origin: *
or response header for a specific request like:
access-control-allow-origin: http://localhost:4221
The message in browsers is not clear to understand: "...The requested resource"
note that:
CORS works well for localhost. different port means different Domain.
if you get error message, check the CORS config on the server side.
In most housing services just add in the .htaccess on the target server folder this:
Header set Access-Control-Allow-Origin 'https://your.site.folder'
I had the same issue. In my case i fixed it by adding addition parameter of timestamp to my URL. Even this was not required by the server I was accessing.
Example yoururl.com/yourdocument?timestamp=1234567
Note: I used epos timestamp
"Get" request with appending headers transform to "Options" request. So Cors policy problems occur. You have to implement "Options" request to your server. Cors Policy about server side and you need to allow Cors Policy on your server side. For Nodejs server:details
app.use(cors)
For Java to integrate with Angular:details
#CrossOrigin(origins = "http://localhost:4200")
You should enable CORS to get it working.
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 *
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.
After reading about CORS (Cross-Origin Resource Sharing), I don't understand how it improves security. Cross-Domain AJAX communication is allowed if the correct ORIGIN header is sent. As an example, if I send
ORIGIN: http://example.com
The server checks if this domain is in the white list and, if it is, header:
Access-Control-Allow-Origin: [received url here]
is sent back, together with the response (This is the simple case, there are also prefighted requests, but the question is the same).
Is this really secure? If someone wants to receive the information, faking an ORIGIN headers seems like a really trivial task. Also the standard says that the policy is enforced in the browser, blocking the response if Access-Control-Allow-Origin is not correct. Obviously if anyone is trying to get that info, he will not use a standard browser to block it.
The purpose is to prevent this -
You go to website X
The author of website X has written an evil script which gets sent to your browser
that script running on your browser logs onto your bank website and does evil stuff and because it's running as you in your browser it has permission to do so.
The ideas is that your bank's website needs some way to tell your browser if scripts on website X should be trusted to access pages at your bank.
Just to add on #jcoder 's answer, the whole point of the Origin header isn’t to protect the resources requested on a server. That task is up to the server itself via other means exactly because an attacker is indeed able to spoof this header with the appropriate tools.
The point of the Origin header is to protect the user.
The scenario is the following:
an attacker creates a malicious website M
a user Alice is tricked to connect to M, which contains a script that tries to perform some actions through CORS on a server B that actually supports CORS
B will probably not have M in its Access-Control-Allow-Origin header, cause why would it?
The pivotal point is that M has no means to spoof or overwrite the Origin header, because the requests are initiated by Alice's browser. So her browser will set the (correct) Origin to M, which is not in the Access-Control-Allow-Origin of B, therefore the request will fail.
Alice could alter the Origin header herself, but why would she, since it would mean she is harming herself?
TL;DR: The Origin header protects the innocent user. It does not secure resources on a server. It is spoofable by an attacker on his own machine, but it cannot be spoofed on a machine not under his control.
Servers should still protect their resources, as a matching Origin header doesn't mean an authorized access. However, a Origin header that does NOT match means an unauthorized access.
You can't fake an Origin header with JavaScript in a web browser. CORS is designed to prevent that.
Outside of a web browser, it doesn't matter. It isn't designed to stop people from getting data that is available to the public. You can't expose it to the public without members of the public getting it.
It is designed so that given:
Alice, a person providing an API designed to be accessed via Ajax
Bob, a person with a web browser
Charlie, a third party running their own website
If Bob visits Charlie's website, then Charlie cannot send JS to Bob's browser so that it fetches data from Alice's website and sends it to Charlie.
The above situation becomes more important if Bob has a user account on Alice's website which allows him to do things like post comments, delete data, or see data that is not available to the general public — since without protection, Charlie's JS could tell Bob's browser to do that behind Bob's back (and then send the results to Charlie).
If you want to stop unauthorized people from seeing the data, then you need to protect it with passwords, SSL client certs or some other means of identity-based authentication/authorization.
The purpose of the same origin policy isn't to stop people from accessing website content generally; if somebody wants to do that, they don't even need a browser. The point is to stop client scripts accessing content on another domain without the necessary access rights. See the Wikipedia entry for Same Origin Policy.
"After reading about CORS, I don't understand how it improves security."
CORS does not improve security. CORS provides a mechanism for servers to tell browsers how they should be accessed by foreign domains, and it tries to do so in a way that is consistent with the browser security model that existed before CORS (namely the Same Origin Policy).
But the Same Origin Policy and CORS have a limited scope. Specifically, the CORS specification itself has no mechanism for rejecting requests. It can use headers to tell the browser not to let a page from a foreign domain read a response. And, in the case of preflight requests, it can ask the browser not to send it certain requests from a foreign domain. But CORS doesn't specify any means for the server to reject (that is, not execute) an actual request.
Let's take an example. A user is logged in to site A via a cookie. The user loads malicious site M, which tries to submit a form that does a POST to A. What will happen? Well, with or without CORS, and with or without M being an allowed domain, the browser will send the request to A with the user's authorization cookie, and the server will execute the malicious POST as if the user initiated it.
This attack is called Cross-Site Request Forgery, and CORS itself does nothing to mitigate it. That's why CSRF protections are so important if you allow requests to change data on behalf of users.
Now, the use of the Origin header can be an important part of your CSRF protection. Indeed, checking it is part of the current recommendation for multi-pronged CSRF defense. But that use of the Origin header falls outside the CORS specification.
In sum, CORS is a useful specification for extending the existing Same Origin Policy security model to other accepted domains. It doesn't add security, and sites need the same kinds of defense mechanisms that they did before CORS.
I am late to answer but I don't think any post here really provides the sought answer. The biggest takeaway should be that the browser is the agent that is writing the origin header value. An evil script cannot write the origin header value. When the server responds back with a Access-Control-Allow-Origin header, the browser tries to ensure that this header contains the origin value sent earlier. If not, it triggers an error and does not return the value back to the requesting script. The other answers to this question present a good scenario to when you would like to deny an answer back to the evil script.
#daniel f also provides a good answer to the question