I have created a WebAPI controller as below
[EnableCors("http://localhost:1234", "*", "*"]
public class DummyController : ApiController
{
public string GetDummy()
{
return "Iam not DUMMY";
}
}
When I hit the service using ajax from my application which is hosted on locahost:5678 It throws error since it is not allowed but when I hit the same API from restclient like PostMan it returns data.
Questions
1) CORS restricts only ajax requests and not the normal HTTP requests because I believe postman sends normal http requests.
2) How does EnableCors restrict to provided origins? Consider if I modify the origin and referrer params in the ajax request I can fish the values. What strategy does CORS use to identify the referrer URL.
As W3C states HttpReferrer can be easily modified, one should not depend on its value to authorize the access. If that is the case What does EnableCors checking in behind to authorize the origin.
I could just change my origin in ajax request also. Please help me with this Iam pretty much confused
CORS restricts only ajax requests and not the normal HTTP requests because I believe postman sends normal http requests.
Yes, specifically browsers restrict Ajax requests — that is, browsers by default don’t allow frontend JavaScript code to access responses from cross-origin requests made with XMLHttpRequest, the Fetch API, or with Ajax methods from JavaScript libraries.
Servers don’t themselves enforce any restrictions on cross-origin requests; instead, servers send responses to any clients that make requests to them, including postman — and including browsers.
Browsers themselves always get the responses that any other client would; but just because the browser gets a response doesn’t mean the browser will allow frontend JavaScript code to access that response. Browsers will only expose a response for a cross-origin request to frontend code if the response includes the Access-Control-Allow-Origin header.
How does EnableCors restrict to provided origins?
It doesn’t. When you CORS-enable a server, the only effect that has is to cause the server to send additional response headers, based on the values of particular request headers it receives — in particular, the Origin request header.
Consider if I modify the origin and referrer params in the ajax request I can fish the values. What strategy does CORS use to identify the referrer URL.
Servers don’t (and can’t) do any validation of the Origin value to confirm it hasn’t been spoofed or whatever. But the CORS protocol doesn’t require servers to do that — because all CORS enforcement is done by browsers.
As W3C states HttpReferrer can be easily modified, one should not depend on its value to authorize the access. If that is the case What does EnableCors checking in behind to authorize the origin.
I could just change my origin in ajax request also. Please help me with this Iam pretty much confused
Browsers know the real origin of any frontend code that sends a cross-origin request, and browsers do CORS checks against what they know to be the real origin of the request — and not against the value of the Origin header.
Browsers are what set the Origin request header and send it over the network to begin with; they set the Origin value based on what they know to be the real origin, and not for their own use — because they already know what the origin is and that value is what they use internally.
So even if you manage to change an Origin header for a request, that won’t matter to the browser — it’s going to ignore that value and continue checking against the real origin.
cf. the answer at
In the respective of security, is it meaningful to allow CORS for specific domains?
Related
I created login FE and finished it.
And as per usual my goto for ajax was Axios. My code is as follows.
const baseUrl = http://localhost:5000/project/us-central1/api
Axios.post(
`${baseUrl}/v1/user/login`,
{ ...data },
{
headers: {
Authorization: 'Basic auth...'
}
},
).then(r => console.log(r).catch(e =>console.log(e));
Now when i try to send request to my local firebase cloud function.
I get a 400 bad request.
after checking the request, I was wondering why it wasn't sending any preflight request, which it should do(to the best of my knowledge) but instead I saw a header named Sec-Fetch-Mode. I searched anywhere it's a bit abstract. And I can't seem to figure anything why my request still fails.
Is there anything Im missing in my config of axios?
My FE is running on a VSCode Plugin named live server(http://127.0.0.1:5500)
Also, my firebase cloud function has enabled cors
// cloud function expres app
cors({
origin: true
})
Any insights would be very helpful.
The OPTIONS request is actually being sent, because you are sending a cross-origin request with an Authorization header which is considered as non-simple. It doesn't show in developer tools because of a feature/bug in Chrome 76 & 77. See Chrome not showing OPTIONS requests in Network tab for more information.
The preflight request is a mechanism that allows to deny cross-origin requests on browser side if the server is not CORS aware (e.g: old and not maintained), or if it explicitly wants to deny cross-origin requests (in both cases, the server won't set the Access-Control-Allow-Origin header). What CORS does could be done on server side by checking the Origin header, but CORS actually protects the user at browser level. It blocks the disallowed cross-origin requests even before they are sent, thus reducing the network traffic, the server load, and preventing the old servers from receiving any cross-origin request by default.
On the other hand, Sec-Fetch-Mode is one of the Fetch metadata headers (Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site and Sec-Fetch-User). These headers are meant to inform the server about the context in which the request has been sent. Based on this extra information, the server is then able to determine if the request looks legitimate, or simply deny it. They exist to help HTTP servers mitigate certain types of attacks, and are not related to CORS.
For example the good old <img src="https://mybank.com/giveMoney?amount=9999999&to=evil#attacker.com"> attack could be detected on server side because the Sec-Fetch-Dest would be set to "image" (this is just a simple example, implying that the server exposes endpoints with the GET method with unsafe cookies for money operations which is obviously not the case in real life).
As a conclusion, fetch metadata headers are not designed to replace preflight requests, but rather to coexist with them since they fulfill different needs. And the 400 error has likely nothing to do with these, but rather with the request that does not comply with the endpoint specification.
You are missing a dot on your spread operator, this is the correct syntax:
{ ...data }
Note the three dots before “data”.
Please see the use of spread operators with objects here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
From my little experience in web API, same origin policy is a policy of browsers i.e, browser doesn't allow to make requests to other hosts rather than the origin. I wonder how it is possible to enable CORS from server side(talking about ASP.net Web API)?
This is how i enable CORS in webAPI
namespace WebService.Controllers
{
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods ...
}
}
If CORS is a browser thing, isn't it more logical to enable it from client side. Can anybody clear this out
Here’s an attempt at a short summary of how it works: The browser is where the same-origin policy and cross-origin restrictions are enforced. Specifically, browsers block frontend JavaScript code from being able to access responses from cross-origin requests—unless the servers the requests are made to send the response header Access-Control-Allow-Origin in responses.
In other words, the way for getting browsers to relax the same-origin policy is for servers to use the Access-Control-Allow-Origin header to indicate they’re opting in to cross-origin requests.
So, browsers are the place where any cross-origin restrictions are either being applied or relaxed.
One case that helps to illustrate how it works is a simple cross-origin POST. As long as a cross-origin POST doesn’t have any custom request headers that will trigger browsers to do a CORS preflight OPTIONS request, a browser will go ahead and make the request, even cross-origin. And the server that POST is sent to will go ahead and accept it and then send a response.
What happens then is where the cross-origin restrictions from browsers kick in—because if that POST request was sent from frontend JavaScript code using XHR or the Fetch API or an Ajax method from some JavaScript library, then unless the response includes the Access-Control-Allow-Origin header, browsers won’t allow the frontend code to access the response (even though the server accepted the POST and it succeeded).
Anyway, I hope the above helps to clarify what enabling CORS support in servers actually means, and what effects it has, and that the actual policy enforcement is performed by browsers.
Of course all of the above just describes the simplest case, where there are no characteristics of the request that will trigger browsers to do a CORS preflight OPTIONS request.
But still in that case, the policy enforcement is all performed by the browser—in fact even more so, in that, for example, browsers won’t allow a POST with custom headers to even be sent to a server to begin with unless the server explicitly indicates (in its response to the preflight OPTIONS) that the server has opted in to receiving cross-origin requests which include that custom header.
MDN says, when the credentials like cookies, authorisation header or TLS client certificates has to be exchanged between sites Access-Control-Allow-Crendentials has to be set to true.
Consider two sites A - https://example1.xyz.com and another one is B- https://example2.xyz.com. Now I have to make a http Get request from A to B. When I request B from A I am getting,
"No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://example1.xyz.com' is therefore not allowed
access."
So, I'm adding the following response headers in B
response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
This resolves the same origin error and I'm able to request to B. When and why should I set
response.setHeader("Access-Control-Allow-Credentials", "true");
When I googled to resolve this same-origin error, most of them recommended using both headers. I'm not clear about using the second one Access-Control-Allow-Credentials.
When should I use both?
Why should I set Access-Control-Allow-Origin to origin obtained from request header rather than wildcard *?
Please quote me an example to understand it better.
Allow-Credentials would be needed if you want the request to also be able to send cookies. If you needed to authorize the incoming request, based off a session ID cookie would be a common reason.
Setting a wildcard allows any site to make requests to your endpoint. Setting allow to origin is common if the request matches a whitelist you've defined. Some browsers will cache the allow response, and if you requested the same content from another domain as well, this could cause the request to be denied.
Setting Access-Control-Allow-Credentials: true actually has two effects:
Causes the browser to actually allow your frontend JavaScript code to access the response if credentials are included
Causes any Set-Cookie response header to actually have the effect of setting a cookie (the Set-Cookie response header is otherwise ignored)
Those effects combine with the effect that setting XMLHttpRequest.withCredentials or credentials: 'include' (Fetch API) have of causing credentials (HTTP cookies, TLS client certificates, and authentication entries) to actually be included as part of the request.
https://fetch.spec.whatwg.org/#example-cors-with-credentials has a good example.
Why should I set Access-Control-Allow-Origin to origin obtained from request header rather than wildcard *?
You shouldn’t unless you’re very certain what you’re doing.
It’s actually safe to do if:
The resource for which you’re setting the response headers that way is a public site or API endpoint intended to be accessible by everyone, and
You’re just not setting cookies that could enable an attacker to get access to sensitive information or confidential data.
For example, if your server code is just setting cookies just for the purpose of saving application state or session state as a convenience to your users, then there’s no risk in taking the value of the Origin request header and reflecting/echoing it back in the Access-Control-Allow-Origin value while also sending the Access-Control-Allow-Credentials: true response header.
On the other hand, if the cookies you’re setting expose sensitive information or confidential data, then unless you’re really certain you have things otherwise locked down (somehow…) you really want to avoid reflecting the Origin back in the Access-Control-Allow-Origin value (without checking it on the server side) while also sending Access-Control-Allow-Credentials: true.
If you do that, you’re potentially exposing sensitive information or confidential data in way that could allow malicious attackers to get to it. For an explanation of the risks, read the following:
https://web-in-security.blogspot.jp/2017/07/cors-misconfigurations-on-large-scale.html
http://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html
And if the resource you’re sending the CORS headers for is not a public site or API endpoint intended to be accessible by everyone but is instead inside an intranet or otherwise behind some IP-address-restricted firewall, then you definitely really want to avoid combining Access-Control-Allow-Origin-reflects-Origin and Access-Control-Allow-Credentials: true. (In the intranet case you almost always want to only be allowing specific hardcoded/whitelisted origins.)
We can set and allow cross-origin-resource-sharing for
All domains , Specific domains and Not allow for any domains
But I wonder allowing CORS for specific domains meaningful.
If a hacker knows the domains that server allows. (e.g www.facebook.com)
Hacker can fake the origin header in the request as www.facebook.com
Thus, in the perspective of security. I think only Allow all domains and Not allow for any domains are meaningful. Since it is very easy to fake the origin of the requester
Am I right??
Browsers are where CORS restrictions are enforced. And browsers know the real origin a script runs in. That’s how they work. If they didn’t, there would be zero security on the Web.
So browsers do CORS checks against what they know to be the real origin of the JavaScript code that’s making an XHR or fetch() request—not against the value of the Origin header.
And browsers are what set the Origin request header and send it over the network to begin with. Browsers set the Origin value based on what they know to be the real origin, and not for their own use—because they already know what the origin is and that value is what they use internally.
So even if you manage to change an Origin header a browser sends over the network, that won’t matter to the browser—it’s going to ignore that value and continue checking against the real origin.
More details
As far as CORS goes, servers just send back documents, with an Access-Control-Allow-Origin header and other CORS headers, to any client that requests them.
Consider if you use curl or something to request a document from a server: The server doesn’t check the Origin header and refuse to send the document if the requesting origin doesn’t match the Access-Control-Allow-Origin header. The server sends the response regardless.
And as far as clients go, curl and non-browser tools don’t have the concept of an origin to begin with and so don’t usually send any Origin header to begin with. You can make curl send one—with any value you want—but it’s pointless because servers don’t care what the value is.
And curl, etc., don’t check the value of the Access-Control-Allow-Origin response header the server sends, and refuse to get a document if the request’s Origin header doesn’t match the Access-Control-Allow-Origin header in the server response. They just get the document.
But browsers are different. Browser engines are really the only clients that have the notion of an origin to begin with, and that know the actual origin a Web application’s JavaScript is running in.
And unlike curl, etc., browsers will not let your script get a document if the XHR or fetch() call requesting it is from an origin not allowed in the server’s Access-Control-Allow-Origin header.
And again, the way browsers determine what the origin is by already knowing what the origin is, not based on the value of whatever Origin request header might end up getting sent in the request.
I am building a web service that exclusively uses JSON for its request and response content (i.e., no form encoded payloads).
Is a web service vulnerable to CSRF attack if the following are true?
Any POST request without a top-level JSON object, e.g., {"foo":"bar"}, will be rejected with a 400. For example, a POST request with the content 42 would be thus rejected.
Any POST request with a content-type other than application/json will be rejected with a 400. For example, a POST request with content-type application/x-www-form-urlencoded would be thus rejected.
All GET requests will be Safe, and thus not modify any server-side data.
Clients are authenticated via a session cookie, which the web service gives them after they provide a correct username/password pair via a POST with JSON data, e.g. {"username":"user#example.com", "password":"my password"}.
Ancillary question: Are PUT and DELETE requests ever vulnerable to CSRF? I ask because it seems that most (all?) browsers disallow these methods in HTML forms.
EDIT: Added item #4.
EDIT: Lots of good comments and answers so far, but no one has offered a specific CSRF attack to which this web service is vulnerable.
Forging arbitrary CSRF requests with arbitrary media types is effectively only possible with XHR, because a form’s method is limited to GET and POST and a form’s POST message body is also limited to the three formats application/x-www-form-urlencoded, multipart/form-data, and text/plain. However, with the form data encoding text/plain it is still possible to forge requests containing valid JSON data.
So the only threat comes from XHR-based CSRF attacks. And those will only be successful if they are from the same origin, so basically from your own site somehow (e. g. XSS). Be careful not to mistake disabling CORS (i.e. not setting Access-Control-Allow-Origin: *) as a protection. CORS simply prevents clients from reading the response. The whole request is still sent and processed by the server.
Yes, it is possible. You can setup an attacker server which will send back a 307 redirect to the target server to the victim machine. You need to use flash to send the POST instead of using Form.
Reference: https://bugzilla.mozilla.org/show_bug.cgi?id=1436241
It also works on Chrome.
It is possible to do CSRF on JSON based Restful services using Ajax. I tested this on an application (using both Chrome and Firefox).
You have to change the contentType to text/plain and the dataType to JSON in order to avaoid a preflight request. Then you can send the request, but in order to send sessiondata, you need to set the withCredentials flag in your ajax request.
I discuss this in more detail here (references are included):
http://wsecblog.blogspot.be/2016/03/csrf-with-json-post-via-ajax.html
I have some doubts concerning point 3. Although it can be considered safe as it does not alter the data on the server side, the data can still be read, and the risk is that they can be stolen.
http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx/
Is a web service vulnerable to CSRF attack if the following are true?
Yes. It's still HTTP.
Are PUT and DELETE requests ever vulnerable to CSRF?
Yes
it seems that most (all?) browsers disallow these methods in HTML forms
Do you think that a browser is the only way to make an HTTP request?