3 ms·
CORS was designed to mitigate e.g. the following attack: * You are logged at with service X, which uses a Cookie to store your authentication code. * Service
by ThePhysicist 8y ago
CORS was designed to mitigate e.g. the following attack:
* You are logged at with service X, which uses a Cookie to store your authentication code.
* Service X offers an endpoint to change your password, as well as an endpoint to retrieve your user account.
* You visit malicious website Y, which uses JS to send requests to the "change password" and "view profile" endpoints of service X (which without CORS would be accepted as the browser sends your authentication cookie with them), getting your profile information and changing your password, thereby taking over your account.
With CORS, for requests from third-party domains the browser first sends an "OPTION" pre-flight request to service X, which would then respond with a set of CORS headers from which the browser can determine if the given domain you're on (Y) is allowed to send requests to the service. If not, the request (e.g. GET, POST, PUT, DELETE) is not even sent. CORS therefore protects the user from malicious websites while still allowing requests from specific third-party domains (as there are legitimate use cases for sending API requests to a third-party website).
Note that CORS does not protect you from user-triggered requests (e.g. actively submitting an HTML form), for which you need CSRF tokens if you use cookies for authentication (which are sent automatically with each request).
- chemicalcrux 8y agoI've always found it interesting how there's a difference between actions the user initiated and those the user did not. You'd think that would be very challenging to enforce, given how flexible browser scripting is nowadays, but it seems to Just Work.
- lostcolony 8y agoThere isn't, though. It really is just the same origin policy at work (or, if you mean more abstractly, the website flagging them differently; you can still construct it into a curl call that will be indistinguishable, barring something like a varying CSRF token that requires the page to be loaded, but again, that can still be faked by loading the page, grabbing the token, and using it in the resulting cURL call). But preventing PUT/POST/DELETE from other origins prevents other origins from making requests on the user's behalf. It also prevents the user from making those requests. It either has to be a GET (which is itself a security hole, but one necessary to the basic utility of the web and which -should- be okay provided people do indeed make GETs idempotent; it has been leveraged into JSON-P, a terrible unsafe hack, though), or it has to use CORS to preflight it. Once you have CORS in place, it's still indeterminate as to whether the action was user initiated or not. It's just that a request originating from origin (X) has been allowed.
- ThePhysicist 8y agoThat's not entirely correct, as you can still create a form on page Y and have it submit a POST request to site X even if CORS is enabled, as CORS does only govern asynchronously triggered requests. So you still need CSRF to fully protect against malicious form submissions from third-party domains.
- lostcolony 8y agoWell, yes. POSTs of the right MIME type also work, not just GETs, due to, again, the way the web worked prior to AJAX and APIs and all that lovely goodness requiring some rethinking the web's security model (back when we had 'submit' forms and that was it). So, technically accurate WRT where the same origin policy applies, but not really relevant to the parent's base statement that you can differentiate between what is and is not user triggered (since you can send a payload in code with the same MIME type and etc so that it looks identical to what a form would send).
- rrosen326 8y agoAha - I think this answers something that has always confused me. If I create a micro-service and want to protect it, CORS doesn't help me very much. I still need some sort of authentication mechanism (perhaps provided in a cookie) to say, "yes - this request is permitted." CORS helps protect that authentication mechanism within a browser. Is that about right?
- jakelazaroff 8y agoYup! CORS is meant to protect a service's users, not the service itself. Services should always authenticate/distrust user input/etc; no client-side technology makes that unnecessary.
- jjnoakes 8y agoIf you need CSRF tokens for forms, etc, then what does CORS give you above CSRF tokens?
- niftich 8y agoCSRF tokens are a popular mitigation against CSRF, where CSRF is a "vulnerability" that arises in part when a user is tricked into asking its user-agent to make a request the user didn't actually intend. This is particularly likely to happen in web browsers because they support hyperlinks or image tags to arbitrary destinations (which turn into GET requests), and support form auto-submission to arbitrary targets (which turn into POST requests). The request will often inherit the user's legitimate authentication posture on the target site, because all cookies and headers are also sent, riding on the user's existing session. Despite all this unpleasantness, a web browser adheres to the 'same-origin policy', which prevents the response from CSRF attack to be made known to the originating site. Given the predominance of interactive user-agents that support the same-origin policy, it's not very likely to be tricked into a CRSF with a user-agent that doesn't adhere to the same-origin policy. CORS isn't a security feature per se, it's a mechanism to selectively relax the same-origin policy to obtain a response from a different source, if that source consents.
- ThePhysicist 8y agoCSRF tokens are usually only used for state-altering requests (POST, GET etc.), though one could use them for GET requests as well. The reason people don't do use CSRF for GET is that there's usually no risk involved when calling a GET endpoint from your browser, as it's not supposed to change the state of a resource in any way. And since an HTML form submission or included link will take the user directly to your API, there's no way for the attacker to extract the information afterwards (which is of course given if the attacker can make the request asynchronously via Javascript). You can also use the "Referer" and "Origin" headers to defend your API against form submission from third-party websites without using any CSRF tokens (as browsers will include the URL/domain of the site from which the form was submitted), though there were numerous cases where browsers or e-mail clients didn't set these headers correctly, so if you really want to be sure the only way is to use a CSRF token. You can put that token e.g. in a JS-readable cookie, which will not be accessible on third-party websites but which you can read out via JS on your domain and then include in the POST/PUT/... request. If you want to run your code from different domains as well you will have to provide an endpoint from which users can get the CSRF token though (as Cookies from your API domain will not be readable there). You will then need to restrict that endpoint using CORS, as otherwise an attacker will be able to get a valid token and e.g. inject that into an HTML form which he/she can then submit. So CORS and CSRF do different things, but for API-based apps that should be able to run on multiple (non-sibling) domains you need both mechanisms to ensure security (and CSRF needs CORS in that case to function).