S3 CORS policy for public bucket - amazon-s3

It seems to be easy, but I don't know what I am missing.
I have a public bucket with a js script that I fetch from my web site. I noticed that I don't send Origin header to S3, it is not required and everything works without any CORS configurations.
What's more, even after I manually added Origin header to that GET call and explicitly disallowed GET and my domain via:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>http://www.nonexistingdomain.com</AllowedOrigin>
<AllowedMethod>POST</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
I can still get the content. What's going on here?

Ok, after a conversation with Quentin, I think I understand where I am misinterpreting how CORS should work.
In Java world, it's a very common practice to actually reject requests when Origin doesn't match. Here is another thread where it's mentioned.
If we take Spring as an example(which is de-facto standard in Java world), here is what happens when CORS filter is added:
String allowOrigin = checkOrigin(config, requestOrigin);
...
if (allowOrigin == null) {
logger.debug("Reject: '" + requestOrigin + "' origin is not allowed");
rejectRequest(response);
return false;
}
where:
/**
* Invoked when one of the CORS checks failed.
*/
protected void rejectRequest(ServerHttpResponse response) {
response.setStatusCode(HttpStatus.FORBIDDEN);
}
You can find the code here.
But to my surprise, it is not such a common practice with other stacks and server-side technologies. Another common approach would be to send whatever CORS configuration they have to the browser and leave the decision to it.
S3 is even more tricky: it only sends CORS response headers when the bucket CORS rules match the CORS-enabled request(a request qith Origin header). Otherwise, there would be no CORS response headers.

The Same Origin Policy is a feature enforced by browsers which prevents JavaScript running on one website from reading data from a different website. (This stops random websites using JavaScript to use your browser to skip past your corporate firewall and access your intranet or read your GMail with your cookies).
CORS lets a website relax the Same Origin Policy to allow other websites to read data from it that way.
CORS is not authentication/authorisation. Your public bucket is public.
You aren't using JavaScript to read data from your bucket, you are loading the JS directly from the bucket.

Let's break down the problem and try to understand the fundamentals of CORS.
What is Cross-Origin Request & CORS?
Cross-Origin Request: A request for a resource (like
an image or a font) outside of the origin is known as a cross-origin
request.
CORS is helpful when you are requesting for a protected resource from another origin.
Cross-Origin Request Sharing: A request for a protected resource (like an image or a font or an XHR request) outside of the origin is known as a cross-origin request.
Why do we need CORS when the resources can be protected by using authentication/authorization tokens?
CORS is the first line of defense. When both the client (e.g., browsers) and servers are CORS-aware, clients will allow only requests from the specific origins to the servers as per instructed by the servers.
By default, browsers are supposed to implement same-origin policy security mechanism as per the guidelines on building the browser. Almost all the modern browser implement same-origin policy that instructs the browsers to allow requests to the servers if the origin is the same.
Same-origin policy is a security mechanism of a browser, you can read more about it here. It is because of this feature of browsers, the browser blocks all the request when the designation origin and the source origin are different. (Servers are not even aware that this is happening, Wow!)
For simpler use cases, when the assets(js, CSS, images, fonts), XHR resources are accessible with the same origin, there is no need to worry about CORS.
If assets are hosted on another origin or XHR resource are hosted on servers with a different domain that the source then browsers will not deny the request to cross-origin by default. Only with appropriate CORS request and response headers, browsers are allowed to make cross-origin requests.
Let's look at the request and response headers.
Request headers
Origin
Access-Control-Request-Method
Access-Control-Request-Headers
Response headers
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Expose-Headers
Access-Control-Max-Age
Access-Control-Allow-Methods Access-Control-Allow-Headers
For setting up CORS the Origin, and Access-Control-Allow-Origin headers are needed. Browsers will automatically add Origin header to every request, so a developer needs to configure only Access-Control-Allow-Origin response header.
For protecting access to resources only from specific domains, S3 provides an option to configure CORS rules. If the value of Access-Control-Allow-Origin header is * all the cross-origin requests are allowed, or else define a comma-separated list of domains.
There are a couple of things you need to be aware of when using CORS.
It's the first level of defense to a protected resource and not the ultimate defense.
You still need to implement appropriate authentication & authorization for the resource to perform CRUD operations on the server.
Implementing Same Origin Policy is a guideline for building the browser and are not mandatory.
CORS headers are useful only when clients accept the headers. Only modern browsers accept CORS headers. If you are not using browsers to make the resource request, then CROS do not apply.
If you type the link in the address bar of the browser, the CORS rules are not applied to because the browser does not send the Origin header to the server. The Origin header is sent by the browser only on the subsequent resource request (stylesheets, js files, fonts) and XHR requests by the origin.
If you access the resource file by directly typing the link in the address bar, the browser does not send Origin header to that request.
Also, if you want to restrict GET access use S3 pre-signed URL on a private bucket.

Related

Firebase auth breaks with cross origin isolation (i.e. when using Cross-Origin-Resource-Policy)

I am trying to make a website cross origin isolated, and enabled the following headers on my site:
https://web.dev/cross-origin-isolation-guide/
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Firebase auth uses a call to:
https://<AUTH_DOMAIN>/__/auth/iframe?apiKey=<API_KEY>&appName=[DEFAULT]
This gets blocked if you and makes authentication fail.
Because your site has the Cross-Origin Embedder Policy (COEP) enabled, each resource must specify a suitable Cross-Origin Resource Policy (CORP). This behavior prevents a document from loading cross-origin resources which don’t explicitly grant permission to be loaded.
To solve this, add the following to the resource’s response header:
Cross-Origin-Resource-Policy: same-site if the resource and your site are served from the same site.
Cross-Origin-Resource-Policy: cross-origin if the resource is served from another location than your website. ⚠️If you set this header, any website can embed this resource.
How does one fix this? It seems like the root issue is that firebase needs to set a header on their side ?

How to enable CORS for Catalyst

Having a Perl Catalyst application, which produces JSON, I need to read that JSON content using jQuery within an HTML page, served by an Apache server. Both applications, Catalyst and Apache are running on the same host.
When I access the Catalyst URL from Apache I get the error
Access to XMLHttpRequest at 'http://localhost:3000/abc/json_list' from origin 'http://localhost:8888' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
As I red in many topics, a header (or more) must be set. In this case the Catalyst must be set but I don't know how.
Any hint?
Catalyst allows you to set response headers using the header method on the response object.
$c->res->header( "Access-Control-Allow-Origin" => "http://localhost:8888" );
Consider using a controller's sub auto or using existing middleware if you have multiple endpoints that need to provide permission via CORS.

Does the presence of an Origin header imply a CORS request

Is it safe to assume that an HTTP request with an Origin header is a CORS request?
If not, what is the correct way to distinguish a CORS request from a regular HTTP request originating from, say, an PHP app on an external server?
If by “CORS request” you mean a cross-origin request—i.e. a request using the CORS protocol—then no, it isn’t safe to assume request with an Origin header is a cross-origin request.
That’s because, along with requiring browsers to send an Origin in all cross-origin requests that use the CORS protocol, the Fetch spec also requires browsers to send the Origin header for all requests whose method is neither GET nor HEAD:
If the CORS flag is set or httpRequest’s method is neither GET nor HEAD, then append Origin/httpRequest’s origin, serialized and UTF-8 encoded, to httpRequest’s header list.
So browsers must also send the Origin header for, e.g., all POST requests.
The Fetch spec further states:
A CORS request is an HTTP request that includes an Origin header. It cannot be reliably identified as participating in the CORS protocol as the Origin header is also included for all requests whose method is neither GET nor HEAD.
So the spec actually defines CORS request to mean “any request that has an Origin header“ — even if that request isn’t cross-origin and so doesn’t use the the CORS protocol.
That may seem like a weird way to define it, but anyway given that, it’s important to remember that anywhere else the spec mentions CORS request, it does not necessarily mean a cross-origin request or even “a request participating in the CORS protocol” — because per the above definition from the spec, a same-origin POST request is also a CORS request.
So, there’s no way from the server side to reliably identify a given request as participating in the CORS protocol. Only the browser sending the request knows—and other than Origin, there are no other headers we can assume browsers will always send in CORS-protocol requests.

Get an API key from external site

I have a site, which uses where2GetIt API. I need to get some data from this site,
but after making request, I get "No 'Access-Control-Allow-Origin' header is present on the
requested resource. Origin 'null' is therefore not allowed access" error.
I assume, that the problem is, that I have not access to API. How can I get the access to API?
If you're doing this with Javascript, make sure you understand CORS
...CORS gives web servers cross-domain access controls, which enable
secure cross-domain data transfers. Modern browsers use CORS in an API
container - such as XMLHttpRequest - to mitigate risks of cross-origin
HTTP requests.
See also this StackOverflow question How does Access-Control-Allow-Origin header work?

How do REST APIs work with JavaScript when the same-origin policy exists for browsers?

I am working with Flickr's REST API and it's working fine. By that, I mean I'm making an AJAX call to the Flickr API and getting a JSON object back, parsing the object, etc. etc.
But this raises a question in my mind. If browsers follow the same-origin policy, then how can they make these types of API requests?
This DEMO fiddle is working, but it sends a cross-domain request to the Flickr domain.
How does this cross-domain request work?
The cross-domain request:
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=" +
id + "&lang=en-us&format=json&jsoncallback=1");
What you need to understand is that, while browsers do enforce the same origin policy (SOP), there are exceptions when SOP is not enforced. For example, if you have an HTML page - you can insert <img> tags that point to images on any domain. Therefore, the SOP doesn't apply here and you are making a cross-origin HTTP GET request for an image.
The demo you linked to works since it uses a mechanism that works in a similar way. The mechanism is called JSONP - http://en.wikipedia.org/wiki/JSONP and I suggest you read the wiki entry and some other blog posts. In essence, JSONP dynamically injects <script> tags to send a request to any domain (the parameters of the request are added as URL query params), since the same origin policy does not apply to <script> tags (as it doesn't apply to <img> tags).
Another way to invoke REST APIs on other domains is to use the cross-origin resource sharing mechanism (CORS) - http://en.wikipedia.org/wiki/Cross-origin_resource_sharing. In essence, this mechanism enables that browsers don't deny cross-origin request, but rather ask the target service if it wants to allow a specific cross-origin request. The target service tells the browser that it wants to allow cross-origin requests by inserting special HTTP headers in responses:
Access-Control-Allow-Origin: http://www.example.com