flutterfire icon indicating copy to clipboard operation
flutterfire copied to clipboard

🐛 [firebase_core_web] TrustedType violations in firebase_core_web.dart - TrustedScript needed

Open jacobsimionato opened this issue 1 year ago • 2 comments

Bug report

Several Google Flutter web apps using Firebase plugins that rely on firebase_core_web are receiving browser error reports through the TrustedTypes browser APIs. Specifically, the script injection code in _injectSrcScript is not adhering to the standards and is causing errors to be logged.

We really want to get this fixed so that we can enable new security features which will protect our apps from certain types of vulnerability.

This was previously reported in https://github.com/firebase/flutterfire/issues/10311 and a fix attempted in https://github.com/firebase/flutterfire/pull/10312, however the fix didn't work (see below). It would be amazing if you could try to reproduce the issue with steps below and verify that using a TrustedScript fixes it.

Currently, we have code like:

    web.TrustedScriptURL? trustedUrl;
    final trustedTypePolicyName = _defaultTrustedPolicyName + windowVar;
    if (web.window.nullableTrustedTypes != null) {
      web.console.debug(
        'TrustedTypes available. Creating policy: $trustedTypePolicyName'.toJS,
      );
      try {
        final web.TrustedTypePolicy policy =
            web.window.trustedTypes.createPolicy(
          trustedTypePolicyName,
          web.TrustedTypePolicyOptions(
            createScriptURL: ((JSString url) => src).toJS,
          ),
        );
        trustedUrl = policy.createScriptURLNoArgs(src);
      } catch (e) {
        throw TrustedTypesException(e.toString());
      }
    }

    final web.HTMLScriptElement script =
        web.document.createElement('script') as web.HTMLScriptElement;
    script.type = 'text/javascript';
    script.crossOrigin = 'anonymous';
    final stringUrl = trustedUrl != null
        // Necessary for the JS interop to work correctly on Flutter Beta 3.19.
        // ignore: unnecessary_cast
        ? (trustedUrl as JSObject).callMethod('toString'.toJS)
        : src;
    script.text = '''
      window.ff_trigger_$windowVar = async (callback) => {
        console.debug("Initializing Firebase $windowVar");
        callback(await import("$stringUrl"));
      };
    ''';

The issue here is that although we do create a trusted types policy to create a TrustedScriptURL (added in the previous fix), we're still "unsafely" setting the text of the Script element (e.g. dynamically creating an inline script) rather than its URL. So even though we embed the DomTrustedScriptUrl in the inline script, overall the entire inner javascript is untrusted. It seems like we should actually use a TrustedScript policy here to create a trusted script to embed - see https://developer.mozilla.org/en-US/docs/Web/API/TrustedScript.

Also see related issue https://github.com/firebase/firebase-js-sdk/issues/7048 which was fixed.

Steps to reproduce the behavior:

  1. Create an example Flutter web app using Firebase

  2. Enable trusted types enforcement, e.g. by adding:

    <meta
      http-equiv="Content-Security-Policy"
      content="require-trusted-types-for 'script'"
     />
    
  3. Load page, and look for errors in the JS console

Expected behavior

Setting the text on the script tag should not produce a trusted types error.

jacobsimionato avatar Feb 08 '24 04:02 jacobsimionato

I was able to replicate it by adding the said meta tag which resulted in below:

Screenshot 2024-02-08 at 5 08 23 PM

Removing the tag built the app properly without any errors.

I used firebase_core plugin example.

darshankawar avatar Feb 08 '24 11:02 darshankawar

Thanks so much for replicating, @darshankawar ! I hope with TrustedScript, we can assign that script src in way that supports trusted types. I'm still not certain whether we also need to use the TrustedScriptURL that is already present, but perhaps you can test that part out.

jacobsimionato avatar Feb 08 '24 22:02 jacobsimionato

Thank you for the quick fix on this!! We'll roll this into Google and give it a try!

jacobsimionato avatar Feb 28 '24 04:02 jacobsimionato