Tracktion / choc

A collection of header only classes, permissively licensed, to provide basic useful tasks with the bare-minimum of dependencies.
Other
529 stars 47 forks source link

webview and local iframes (Access-Control-Allow-Origin) #42

Closed dbadb closed 7 months ago

dbadb commented 8 months ago

I have a situation where my local "website" wants to load local "sub-websites" into their own iframe.

Mostly this works but if the external "website" loads a font-file via its private css, we get interesting CORS errors like these

Access to font at 'choc://choc.choc/C:/path/to/subwebsite/fonts/Wierd.ttf' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I found that adding "Access-Control-Allow-Origin: *" to the resource-served headers (cf near line 1321 of choc_WebView.h) resolves the issue. This probably doesn't introduce any more security concerns than those represented by any WebView app running with full privileges on a user's computer.

Happy to submit a PR on request. cheers

julianstorer commented 8 months ago

The fix you're suggesting would be just to the Windows code - have you tried it on other platforms?

Add the header would clearly work, but I wonder if it still works with restricted access to only the internal resource domain, e.g. Access-Control-Allow-Origin: choc://choc.choc ?

dbadb commented 8 months ago

I have yet to try the other platforms though I made the same simple change in 3 places in my branch.

For more context, the behavior I'm after is for safe sandboxing as described here.

When creating a safe iframe sandbox, the iframe origin is explicitly != the parent origin so this is why explicitly setting ACAO to eg choc://choc.choc doesn't work. This is the implicit default behavior.

One can create a sandboxed iframe with "allow-same-origin" and probably achieve a similar result. The problem with this is that it grants access to iframe javascript to other aspects of the parent environment (localStorage and even the entire parent DOM).

The approach outlined here is to allow the "server" to serve any file it likes constraining access by datatypes or URL by returning 404 when it detects the null origin.

jdv85 commented 7 months ago

For what it's worth, I've just had a similar problem trying to load a resource from JavaScript using fetch(). The following change works for me on macOS:

diff --git a/gui/choc_WebView.h b/gui/choc_WebView.h
index 25983ef..8dd5f92 100644
--- a/gui/choc_WebView.h
+++ b/gui/choc_WebView.h
@@ -478,8 +478,8 @@ private:
                 const auto& [bytes, mimeType] = *resource;

                 auto contentLength = std::to_string (bytes.size());
-                id headerKeys[]    = { getNSString ("Content-Length"), getNSString ("Content-Type"), getNSString ("Cache-Control") };
-                id headerObjects[] = { getNSString (contentLength),    getNSString (mimeType),       getNSString ("no-store") };
+                id headerKeys[]    = { getNSString ("Content-Length"), getNSString ("Content-Type"), getNSString ("Cache-Control"), getNSString ("Access-Control-Allow-Origin") };
+                id headerObjects[] = { getNSString (contentLength),    getNSString (mimeType),       getNSString ("no-store") ,     getNSString ("*") };

                 id headerFields = call<id> (getClass ("NSDictionary"), "dictionaryWithObjects:forKeys:count:",
                                             headerObjects, headerKeys, sizeof (headerObjects) / sizeof (id));

Using choc://choc.choc instead of * also solves my problem.

dbadb commented 7 months ago

@jdv85 just for completeness can you describe what your fetch url and origin looks like?

  1. does the fetch url include a uri_scheme or is it just a www-relative path (choc://choc.choc/path-to-resource or /path-to-resource)?
  2. is your fetch invoked from within an iframe context or is this just a standard fetch request?
jdv85 commented 7 months ago

@dbadb,

  1. does the fetch url include a uri_scheme or is it just a www-relative path (choc://choc.choc/path-to-resource or /path-to-resource)?

Both work for me.

  1. is your fetch invoked from within an iframe context or is this just a standard fetch request?

I'm not using iframe, sorry for not being clear about that in the first place.

julianstorer commented 7 months ago

Thanks - this does seem pretty simple, I've pushed some changes to develop. Let me know if you have any problems with them.

dbadb commented 7 months ago

just did the integrate and can confirm functionality on win32 and apple platform so far.