Why are cross-origin isolation and CORB/CORP both needed? - websecurity

Abbreviations used:
CORP: Cross Origin Resource Policy
CORS: Cross Origin Resource Sharing
CORB: Cross Origin Read Blocking
SSCAs: speculative side-channel attacks, like Spectre
I've read this article, but I still don't understand why are cross-origin isolation and CORB/CORP both needed. Specifically:
If webpages can perform SSCAs without using cross-origin isolated features (like SharedArrayBuffer), which is what Chromium assumes:
Why is it necessary to be cross-origin isolated to have access to those features?
Otherwise, if webpages can't perform SSCAs without using cross-origin isolated features:
Why are CORB and CORP needed?
Also, since webpages can perform SSCAs using cross-origin isolated features, what is the difference between using Cross-Origin-Resource-Policy: cross-origin and Access-Control-Allow-Origin: *, since SSCAs can be used to read data just by embedding a resource and Access-Control-Allow-Origin: * isn't needed for it?

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 ?

S3 CORS policy for public bucket

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.

Cloufdront Masks User Agent and Remote Address

We are running an SPA that communicates with an API. Both are exposed to the public via Cloudfront.
We now have the issue that the requests we see in the backend are masked by Cloudfront. Meaning:
The Remote Address we see is the address of the AWS Cloud
The User Agent Header field is set to "Amazon Cloudfront" and not the browser of the user
So Cloudfront somehow intercepts the request in a way we didn't anticipate.
I already went through these steps: https://aws.amazon.com/premiumsupport/knowledge-center/configure-cloudfront-to-forward-headers/ but ended up cutting the connection between the API and the frontend.
We don't care about caching implications (we don't have a lot of traffic), we just need to the right fields to show up in the backend.
By default, most request headers are removed, because CloudFront's default behaviors are generally designed around optimal caching. CloudFront's default header handling behavior is documented.
If you need to see specific headers at the origin, whitelist those headers for forwarding in the cache distribution. The documentation refers to this as “Selecting the Headers on Which You Want CloudFront to Base Caching” -- and that is what it does -- but that description masks what's actually happening. CloudFront removes the rest of the headers because it has no way of knowing for certain whether a specific header with a certain value might change the response that the origin generates. If it didn't remove these headers by default, there would be confusion in the other direction when users saw the "wrong" responses served from the cache.
In your case, you almost certainly don't want to include the Host header in what you are whitelisting for forwarding.
When testing, especially, be sure you also set the Error Caching Minimum TTL to 0, because the default value is 300 seconds... so you can't see whether the problem is fixed for up to 5 minutes after you fix it. This default is also by design, a protective measure to avoid overloading your origin with requests that are likely to continue to fail.
When examining responses from CloudFront, keep an eye on the Age response header, which is present any time the response is served from cache. It tells you how long it's been (in seconds) since CloudFront obtained the response it is currently returning to you.
If you want to disable CloudFront caching, you can set Maximum, Minimum, and Default TTL all to 0 (this only affects 2xx and 3xx HTTP responses -- errors are cached for a different time window, as noted above), or your origin can consistently return Cache-Control: s-maxage=0, which will prevent CloudFront from caching the response.

CSRF tokens - Do we need to use them in most cases?

So I essentially went on an epic voyage to figure out how to implement CSRF tokens. 20 years later - and now I feel like I just wasted my life. haha
So basically after making malicious test-clients and doing some re-reading it looks like it's virtually not a problem if:
1) You don't allow outdated browsers(they don't enforce CORS)
2) You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
3) You use a JSON API(all requests-responses is sending JSON).
4) You take care of XSS(they can inject code that will run from same origin ).
So as long as you take care of XSS(Reactjs! Holla) - all of the above(minus the old browser part I guess) is basically common practice and an out-of-the-box setup - so it seems like a waste of time to worry about csrf tokens.
Question:
So in order to avoid throwing my laptop under a moving car - is there any reason that I did all that work adding CSRF tokens if I am already adhering to the 4 prevention strategies mentioned above?
Just Fun Info - wanted to share one juicy find my tests came across:
The only ify thing I found with my tests is "GET" requests and an image tag
e.g.
<img src="http://localhost:8080/posts" onload={this.doTheHackerDance} />
The above will pass your cookie, and therefore access the endpoint successfully, but apparently since it is expecting an image - it returns nothing - so you don't get to do the hacker dance. :)
BUUUUT if that endpoint does other things besides return data like a good little "GET" request(like update data) - a hacker can still hit a "dab!" on ya (sorry for viral dance move reference).
tl;dr - Requiring JSON requests mitigates CSRF, as long as this is checked server-side using the content-type header.
Do we need to use them in most cases?
In most other cases, yes, although there are workarounds for AJAX requests.
You don't allow outdated browsers(they don't enforce CORS)
You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
CORS is not required to exploit a CSRF vulnerability.
If Bob has cookies stored for your site, CORS allows your site to allow other sites to read from it, using Bob's browser and cookies.
CORS weakens the Same Origin Policy - it does not add additional security.
The Same Origin Policy (generally - see below for caveat) does not prevent the request from being made to the server, it just stops the response being read.
The Same Origin Policy does not restrict non-Javascript requests in any way (e.g. POSTs made by <form> or <img> HTML directives).
Browsers that do not support CORS, also do not support AJAX cross-origin requests at all.
Therefore while not outputting CORS headers from your site is good for other reasons (other sites cannot access Bob's session), it is not enough to prevent CSRF.
You use a JSON API(all requests-responses is sending JSON).
Actually, if you are setting the content-type to application/json and verifying this server-side, you are mitigating CSRF (this is the caveat mentioned above).
Cross-origin AJAX requests can only use the following content-types:
application/x-www-form-urlencoded
multipart/form-data
text/plain
and these requests are the only ones that can be made using HTML (form tags or otherwise).
You take care of XSS(they can inject code that will run from same
origin ).
Definitely. XSS is almost always a worse vulnerability than CSRF. So if you're vulnerable to XSS you have other problems.
BUUUUT if that endpoint does other things besides return data like a
good little "GET" request(like update data) - a hacker can still hit a
"dab!" on ya (sorry for viral dance move reference).
This is why GET is designated as a safe method. It should not make changes to your application state. Either use POST as per the standard (recommended), or protect these GETs with CSRF tokens.
Please just follow OWASP's guidelines: "General Recommendation: Synchronizer Token Pattern". They know what they're doing.
CSRF counter-measures are not hard if you're using a framework. It's dead simple with Spring Security for example. If you're not using a security framework, you're screwing up big time. Keep it simple. Use one general method to protect against CSRF which you can use on many types of projects
CSRF is orthogonal to CORS . You are vulnerable even if you disallow CORS on your server and your users use the latest Chrome. You can CSRF with HTML forms and some JavaScript.
CSRF is orthogonal to XSS . You are vulnerable even if you have no XSS holes on your server and your users use the latest Chrome
CSRF can happen against JSON APIs. Rely on Adobe keeping Flash secure at your own peril
The new SAMESITE cookie attribute will help, but you need anti-CSRF tokens until then.
Keep reading

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