Skip to content

Accessing contentWindow on cross domain iframes with static js interop doesn't work #54938

Closed
dart-lang/web
#291

Description

@jezell

A security exception is thrown when trying to access the contentWindow property of a cross domain iframe using static interop:

frame.contentWindow!.postMessage(...)

Given the same setup using non static interop, the call succeeds:

(frame as html.IFrameElement).contentWindow!.postMessage(...)

It blows up here in the rtti:

      default:
        // The interceptors for native JavaScript types like bool, string, etc.
        // (excluding number and function, see above) are stored as a symbolized
        // property and can be accessed from the native value itself.
        classRef = JS('', '#[#]', obj, _extensionType);
        

With this message:


Uncaught DOMException: Failed to read a named property from 'Window': Blocked a frame with origin "http://localhost:8002" from accessing a cross-origin frame.
   at Object.getInterceptorForRti (http://localhost:8002/dart_sdk.js:12719:27)
   at dart_rti.Rti.new._isTestViaProperty (http://localhost:8002/dart_sdk.js:24534:28)
   at dart_rti.Rti.new._generalNullableIsTestImplementation (http://localhost:8002/dart_sdk.js:24525:24)
   at dart_rti.Rti.new._generalNullableAsCheckImplementation (http://localhost:8002/dart_sdk.js:24563:28)
   at Object.getProperty (http://localhost:8002/dart_sdk.js:71713:18)
   ...
   at internalCallback (http://localhost:8002/dart_sdk.js:37398:11)
   

It appears something about the rtti check is accessing a property that is locked down on cross domain frames when trying to get the Window object, but I'm unable to step deeper into the stack in the devtools to see exactly the property that is being checked.

Activity

  1. dart-github-bot commented on Feb 16, 2024

    @dart-github-bot
    Collaborator
    Item Details
    Summary Static interop fails to access contentWindow on cross-domain iframes due to security exception.
    Triage to area-dart-cli (medium confidence)

    (what's this?)

  2. added
    area-web-jsIssues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.
    on Feb 16, 2024
  3. sigmundch commented on Feb 16, 2024

    @sigmundch
    Member

    cc @nshahan @fishythefish - I believe this wouldn't affect the dart2js compiler due to differences in how we lookup the interceptor there, but it's worth checking nonetheless.

  4. jezell commented on Feb 16, 2024

    @jezell
    Author

    Can repro similar behavior in JS trying to access properties that don't exist on a cross domain iframe.

    var frame = document.createElement("iframe")
    frame.src = "https://some_other_domain.com";
    frame.contentWindow["property_that_does_not_exist"]; // throws

    however

    var frame = document.createElement("iframe")
    frame.src = "https://some_other_domain.com";
    frame.contentWindow["property_that_does_not_exist"] = 1;
    frame.contentWindow["property_that_does_not_exist"]; // doesn't throw

    So it is checking to see if it is a dart object or a js object, but that can't be done without an exception being thrown on the Window object since it is cross domain. Perhaps the an exception looking up the symbol could be handled and then the symbol set to null in the catch for a minimal performance penalty so it only happens first time around?

  5. nshahan commented on Feb 16, 2024

    @nshahan
    Contributor

    @jezell Thanks for the helpful report!

    @sigmundch I agree with your assessment. The code referenced here is only run in DDC. If dart2js has a problem finding the interceptor for cross origin values it will need to be addressed separately. Would dart2js allow for apps from different frames to pass Dart values between them or are they forced to do some type of conversion to a JavaScript interop value first?

    If there isn't any Dart to Dart object passing allowed then in DDC it seems like the right thing to do here is to treat any cross origin value as a LegacyJavaScriptObject. We just need to find the right way to test for that as efficiently as possible.

  6. sigmundch commented on Feb 16, 2024

    @sigmundch
    Member

    cc @rakudrama

    precisely - I think treating it as JSObject makes sense.

    Anything sent between separate apps (whether they are on the same page or separate iframes) will need to go through interop, and as a result is treated as JS values. Even if you send raw unboxed value through the interop boundary (bypassing some interop conversions), all RTI data is isolated, so it will be viewed as a JS object.

  7. srujzs commented on Feb 16, 2024

    @srujzs
    Contributor

    Similar issue: #54443. It's possible we may come across other issues here even if this specific bug is fixed in the RTI.

  8. DanTup commented on Mar 27, 2024

    @DanTup
    Collaborator

    The Flutter sidebar in VS Code is failing with what seems like the same error:

    Dart-Code/Dart-Code#5049

    The sidebar (part of Flutter DevTools) is hosted inside a sandboxed iframe in VS Code and trying to communicate with its parent using window.parent?.postMessage

    If this isn't a simple fix, are there any reasonable workarounds we could apply to that code?

  9. jezell commented on Mar 27, 2024

    @jezell
    Author

    @DanTup As a workaround, I believe you can cast to the old dart:html version which doesn't have the problem.

  10. srujzs commented on Mar 27, 2024

    @srujzs
    Contributor

    That issue seems more like #54443 considering it's dart2js, but it's a similar issue around cross-domain frames. The error seems to arise from _generalNullableAsCheckImplementation, indicating there's a downcast with a nullable type.

    Looking at the source I wonder if it's parent?.postMessage triggering this. Parker is using a workaround with getProperty to work around this. Maybe that can help here too, but I'll need to look at the JS code to determine which part is the issue. Is there a good way to repro this and get the sources?

  11. DanTup commented on Mar 27, 2024

    @DanTup
    Collaborator

    @srujzs you can repro this using VS Code and Flutter master (just try to load the Flutter Sidebar), but it's probably not very easy to debug that way (however I don't know if it can easily be reproduced outside of it because of the sandboxed iframe etc.).

    You can click Help -> Toggle Developer Tools in VS Code to open the Chrome DevTools.

    I'll see if getProperty helps.

  12. 1 remaining item

  13. DanTup commented on Mar 27, 2024

    @DanTup
    Collaborator

    Oh by the way, you can get at the source from your Flutter SDK checkout (be on master, not stable):

    flutter\bin\cache\dart-sdk\bin\resources\devtools\main.dart.js

    (let me know if I should move this to another issue since it sounds like it might not be the same)

    For convenience, here's the bit of code I suspect you care about:

      A.DartToolingApiImpl_DartToolingApiImpl$postMessage_closure.prototype = {
        call$1(message) {
          var t1 = type$.nullable_JavaScriptObject._as(type$.JavaScriptObject._as(self.window).parent);
          if (t1 != null)
            A.callMethod(t1, "postMessage", [A.jsify(message), "*"], type$.void);
        },
        $signature: 7
      };
  14. srujzs commented on Mar 27, 2024

    @srujzs
    Contributor

    (following up in flutter/devtools#7476 - thanks for all the details!)

  15. jezell commented on Aug 8, 2024

    @jezell
    Author

    This is still blocking us from being able to move to package:web.

  16. mraleph commented on Aug 8, 2024

    @mraleph
    Member

    Can we bump priority of fixing this? cc @natebiggs

  17. srujzs commented on Aug 8, 2024

    @srujzs
    Contributor

    Yeah, I don't see a usable workaround for this like we had with the Window wrapper in dart:html that wrapped dynamic. I'll work on seeing if we can get a wrapper like that in package:web next.

  18. self-assigned this
    on Aug 8, 2024
  19. added
    P1A high priority bug; for example, a single project is unusable or has many test failures
    on Aug 8, 2024
  20. biggs0125 commented on Aug 8, 2024

    @biggs0125

    @srujzs and I talked about this earlier. We've prioritized finding a solution here.

    We want to make sure that it's an separate opt-in API for cases where a user knows they might be dealing with a x-domain object. Given the need for extra interceptor logic/a wrapper we want to make sure we don't degrade other interop use cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1A high priority bug; for example, a single project is unusable or has many test failuresarea-web-jsIssues related to JavaScript support for Dart Web, including DDC, dart2js, and JS interop.web-dev-compilerweb-js-interopIssues that impact all js interop

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions