When should I really set "Access-Control-Allow-Credentials" to "true" in my response headers? - http

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.)

Related

What's the point of Access-Control-Allow-Credentials?

The default value for sending cookies is SameSite=Lax, which means cookies are sent for GET requests, but blocked for POST.
With a cross origin GET request, the response is blocked anwyay due to the Same-Origin-Policy, unless the response contains Access-Control-Allow-Origin.
Why isn't Access-Control-Allow-Origin enough?
Why would you ever want to return Access-Control-Allow-Origin: someDomain.com without also returning Access-Control-Allow-Credentials?
Why allow a cross origin GET request from a trusted domain, but block the response only if the cookie was sent?
Allowing cross-origin sharing is much riskier in the presence of cookies, since that's what can reveal a user's private information to a malicious script. Without cookies, the script can only access public information—the same information that could be accessed by just navigating to the URL from any computer.
So the existence of the Access-Control-Allow-Credentials marks an important security inflection point, and usefully distinguishes between sharing public and private information.
For example, let's say you have an API that's distributing stock ticker data and you want to allow scripts from other sites to access this API. CORS is necessary since the Same Origin Policy will otherwise prevent those scripts from seeing the data. There's no need for cookies, though. So the site can simply use * for Access-Control-Allow-Origin and be done. There's no risk of sharing any private data.
By contrast, a site that wants to enable the sharing of user-specific data will have to opt-in by setting Access-Control-Allow-Credentials to true. Moreover, the site is forced to specify the specific sites allowed, since * is not valid for Access-Control-Allow-Origin in this case.

What is an HTTP server expected to do when it receives an "Origin: null" header? (CORS)

The definition of the Origin header says:
origin-or-null = origin / %s"null" ; case-sensitive
Is "null" to be managed like a domain name? In other words, can the server accept requests when "null" was used (at least in some circumstances) or is it considered like a fault all the time?
I've looked for an explanation in the Fetch Documentation but so far I've not found an answer to this specific question.
By sending an Origin: null header, a browser is indicating the request is from an opaque origin. That is, the browser is signaling to you as a server maintainer that the request wasn’t initiated in a typical way from an app actually running on the web and using an Ajax method or Fetch or XHR to call your server — so it’s probably not a use case which you actually intend your service to support.
So you generally don’t want to send the Access-Control-Allow-Origin response header when responding to Origin: null requests. In other words, you want browsers to block any frontend JavaScript code from access to the response you send back for such requests.
While the most-common case when browsers set the Origin header to null is probably when frontend code is being run from somebody’s local filesystem (from a file:// URL, instead of from a Web server) — there are a number of other cases where browsers also set the Origin header to null. For an exhaustive list, see https://stackoverflow.com/a/42242802/441757.
https://w3c.github.io/webappsec-cors-for-developers/#avoid-returning-access-control-allow-origin-null has an explanation of how you should look at such cases:
It may seem safe to return Access-Control-Allow-Origin: "null" , but the serialization of the Origin of any resource that uses a non-hierarchical scheme (such as data: or file:) and sandboxed documents is defined to be "null". Many User Agents will grant such documents access to a response with an Access-Control-Allow-Origin: "null" header, and any origin can create a hostile document with a "null" Origin. The "null" value for the ACAO header should therefore be avoided.
In other words, you may think it’d be useful to send back Access-Control-Allow-Origin for Origin: null requests if you intentionally want to allow responses from your server to be consumed in frontend JavaScript code running on somebody’s local filesystem (e.g., for somebody doing local testing). But by doing that, you’d not be allowing just the local-filesystem case but also all the other cases described in https://stackoverflow.com/a/42242802/441757. It’s all or nothing.

How does EnableCors restrict the origin access

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?

Nginx: allow only certain cookies in http response

I'm using playframework and nginx. playframework may add following cookies to http response: PLAY_SESSION, PLAY_FLASH, PLAY_LANG.
I want to make sure that only above cookies (PLAY_*) are allowed in nginx level. If there are other cookies (let's say they're added accidentally) they should be removed by nginx.
How can I allow only predefined cookies in http response in nginx?
PS: If it's not possible to solve this issue in nginx, I need to fix by using playframework.
How cookies work?
First, let's establish what's cookies — they're little pieces of "sticky" hidden information that lets you keep state on your web-site for a given User-Agent. These cookies are often used for tracking users, keeping session and storing minor preference information for the site.
Set-Cookie HTTP response header (from server to client)
Cookies can be set by the server through the Set-Cookie response header (with a separate header for each cookie), or, after the page has already been transferred from the server to the client, through JavaScript.
Note that setting cookies is a pretty complex job — they have expiration dates, http/https settings, path etc — hence the apparent necessity to use a separate Set-Cookie header for each cookie.
This requirement to have a separate header is usually not an issue, since cookies aren't supposed to be modified all that often, as they usually store very minimal information, like a session identifier, with the heavy-duty information being stored in an associated database on the server.
Cookie HTTP request header (from client to server)
Regardless how they were first set, cookies would then included in eligible subsequent requests to the server by the client, using the Cookie request header, with a whole list of eligible cookies in one header.
Note that, as such, these cookies that are sent by the client back to the server is a simple list of name and attribute pairs, without any extra information about the underlying cookies that store these attributes on the client side (e.g., the expiration dates, http/https setting and paths are saved by the client internally, but without being revealed in subsequent requests to the server).
This conciseness of the Cookie request header field is important, because, once set, eligible cookies will be subsequently included in all forthcoming requests for all resources with the eligible scheme / domain / path combination.
Caching issues with cookies.
The normal issue of using cookies, especially in the context of acceleration and nginx, is that:
cookies invalidate the cache by default (e.g., unless you use proxy_ignore_headers Set-Cookie;),
or, if you do sloppy configuration, cookies could possibly spoil your cache
e.g., through the client being able to pass cookies to the upstream in the absence of proxy_set_header Cookie "";,
or, through the server insisting on setting a cookie through the absence of proxy_hide_header Set-Cookie;.
How nginx handles cookies?
Cookie from the client
Note that nginx does support looking through the cookies that the client sends to it (in the Cookie request header) through the $cookie_name scheme.
If you want to limit the client to only be sending certain cookies, you could easily re-construct the Cookie header based on these variables, and send only whichever ones you want to the upstream (using proxy_set_header as above).
Or, you could even make decisions based on the cookie to decide which upstream to send the request to, or to have a per-user/per-session proxy_cache_key, or make access control decisions based on the cookies.
Set-Cookie from the backend
As for the upstream sending back the cookies, you can, of course, decide to block it all to considerably improve the caching characteristics (if applicable to your application, or parts thereof), or fix up the domain and/or path with proxy_cookie_domain and/or proxy_cookie_path, respectively.
Otherwise, it's generally too late to make any other routing decision — the request has already been processed by the selected upstream server, and the response is ready to be served — so, naturally, there doesn't seem to be a way to look into these individual Set-Cookie cookies through normal means in nginx (unless you want to go third-party modules, or lua, or perl), since it'd already be too late to make any important routing decisions for a completed request.
Basically, these Set-Cookie cookies have more to do with the content than with the way it is served or routed, so, it doesn't seem appropriate to have integrated functionality to look into them through nginx.
(If you do need to make routing decisions after the completion of the request, then nginx does support X-Accel-Redirect, as well as some other special headers.)
If your issue is security, then, as I've pointed out above, the upstream developer can already use JavaScript to set ANY extra cookies however they want, so, effectively, trying to use nginx to limit some, but not all, Set-Cookie responses from the server is kind of a pointless endeavour in the real world (as there is hardly any difference between the cookies set through JavaScript compared to Set-Cookie).
In summary:
you can easily examine and reconstruct the Cookie header sent by the client to the server before passing it over to the backend, and only include the sanctioned cookies in the request to upstream backend,
but, unless you want to use lua/perl, or have your own nginx module (as well as possibly quarantine the JavaScript from the pages you serve), then you cannot pass only certain Set-Cookie headers back from the upstream backend to the client with a stock nginx.conf — with the Set-Cookie headers, it's an all-or-nothing situation, and there doesn't seem to be a good-enough use-case for a distinct approach.
For an Nginx solution it might be worth asking over at serverfault. Here is a potential solution via Play Framework.
package filters
import javax.inject._
import play.api.mvc._
import scala.concurrent.ExecutionContext
#Singleton
class ExampleFilter #Inject()(implicit ec: ExecutionContext) extends EssentialFilter {
override def apply(next: EssentialAction) = EssentialAction { request =>
next(request).map { result =>
val cookieWhitelist = List("PLAY_SESSION", "PLAY_FLASH", "PLAY_LANG")
val allCookies = result.newCookies.map(c => DiscardingCookie(c.name))
val onlyWhitelistedCookies = result.newCookies.filter(c => cookieWhitelist.contains(c.name))
result.discardingCookies(allCookies: _*).withCookies(onlyWhitelistedCookies: _*)
}
}
}
This solution utilizes Filters and Result manipulation. Do test for adverse effects on performance.

In the respective of security, is it meaningful to allow CORS for specific domains?

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.

Resources