Skip to content

fix(runtime): prefer using globalThis directly#3108

Closed
danhorvath wants to merge 3 commits intomodule-federation:mainfrom
danhorvath:fix-csp-eval-violation
Closed

fix(runtime): prefer using globalThis directly#3108
danhorvath wants to merge 3 commits intomodule-federation:mainfrom
danhorvath:fix-csp-eval-violation

Conversation

@danhorvath
Copy link
Copy Markdown

Description

When getting a reference to the global this, the current code tries to run new Function('return this')() which is blocked by most CSPs. While the fallback code in the catch runs fine so there's no runtime error, the CSP violations still might get reported which pollutes the tracking data.

This PR changes the logic so it prefers returning globalThis directly, similarly to the webpack runtime:

__webpack_require__.g = (() => {
if (typeof globalThis === 'object') return globalThis;
try {
return this || new Function('return this')();
} catch (e) {
if (typeof window === 'object') return window;
}
})();

Related Issue

Fixes #3103

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have updated the documentation.

The workaround to getting globalThis via evaluating "return this" gets blocked by commonly used CSPs
and running it can results in an increased number of CSP violations being tracked.

fix module-federation#3103
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Oct 23, 2024

⚠️ No Changeset found

Latest commit: ee5532c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify
Copy link
Copy Markdown

netlify bot commented Oct 23, 2024

Deploy Preview for module-federation-docs ready!

Name Link
🔨 Latest commit ee5532c
🔍 Latest deploy log https://app.netlify.com/sites/module-federation-docs/deploys/67254fba2afe5000083fef08
😎 Deploy Preview https://deploy-preview-3108--module-federation-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@2heal1
Copy link
Copy Markdown
Member

2heal1 commented Oct 25, 2024

hmm return new Function('return this') is for solving micro-fe sandbox issue , so it can not be changed , but i think we can solve CSP by other way

@2heal1
Copy link
Copy Markdown
Member

2heal1 commented Oct 25, 2024

I see the pr not remove new Function(return this) , so how about this :

export const nativeGlobal: typeof global = (() => {
  try {
    return new Function('return this')();
  } catch {
    return this || globalThis || window
  }
})() as typeof global;

@danhorvath
Copy link
Copy Markdown
Author

That wouldn't solve the original issue unfortunately. As long as the code tries to evaluate new Function('return this')(), that will be a CSP violation and therefore will be reported by certain tools.
The reason why the webpack runtime doesn't have the same issue is that it doesn't attempt to evaluate new Function('return this')() as long as there's a valid globalThis.

@danhorvath
Copy link
Copy Markdown
Author

would it be possible to detect the if the sandboxing issue that you mentioned is present and run the new Function('return this')() conditionally based on that?

@ScriptedAlchemy
Copy link
Copy Markdown
Member

Eval try catch should work tho. Pretty sure someone else had same problem and I just wrapped it in catch and it worked

@ScriptedAlchemy
Copy link
Copy Markdown
Member

Or you can instead check for webpack_require.g if that exists call the runtime function from webpack else run our own fallbacks when outside of webpack

@kimsey0
Copy link
Copy Markdown

kimsey0 commented Oct 30, 2024

Try-catch works in the sense that the code runs, but for all sites with a Content Security Policy, it logs an error to the console and sends a Content Security Policy report for every single user that loads the site. This leads to an incredible amount of CSP report spam to whichever solution you use to aggregate these reports and detect XSS attacks.

eval and similar functions that can execute arbitrary strings containing code are blocked by CSP by default because they're large vectors for Cross-Site Scripting (XSS) attacks. It is possible to enable them again with the unsafe-eval directive, but as should be clear from the name, that's considered unsafe and would not be acceptable to most people who deploy a CSP.

The best solution for us would be any solution that doesn't try running eval at all in browsers. (CSP's do not apply outside browsers, for example in Node.js.)

@ScriptedAlchemy
Copy link
Copy Markdown
Member

Yeh i went and read the Chromium issue about this. Catch works but still throws.

Best option would be to try require.g to use webpacks runtime module, if no webpack runtime, then ours kicks in

@rasmus0201
Copy link
Copy Markdown

rasmus0201 commented Oct 31, 2024

I have this exact issue, and since it's the host that controls the CSP we can't do anything about it (we just deploy the micro frontend). I'm using the @module-federation/vite plugin to build, so the __webpack_require__.g runtime won't exist.

It would be great if the implementation could not attempt to eval. According to the host administrator, in production it would not be able to load the script because of the unsafe-eval rule. So currently we can't use module-federation/core or module-federation/vite because of this.

I also think the best bet is to try and figure out if in sandbox and then run the unsafe eval code like described here #3108 (comment)

@danhorvath
Copy link
Copy Markdown
Author

would it be possible to detect the if the sandboxing issue

if this is not done easily, another option could be to make it configurable whether the eval is attempted here? That could solve the CSP issue for both our usecase (rsbuild) and for vite

@ScriptedAlchemy
Copy link
Copy Markdown
Member

You can check the typeof webpack require. If it exists, use require.g if it exists.

Or check if it's webpack; else if it's vite, lose the sandbox prevention.

@ScriptedAlchemy
Copy link
Copy Markdown
Member

ScriptedAlchemy commented Nov 1, 2024

I have pushed an update to this PR, hows that?

export const nativeGlobal: typeof global = (() => {
  //@ts-ignore
  if (typeof __webpack_require__ !== 'undefined') {
    //@ts-ignore
    if (__webpack_require__.g) {
      //@ts-ignore
      return __webpack_require__.g;
    }
    try {
      return new Function('return this')();
    } catch (e) {
      if (typeof window === 'object') return window;
      if (typeof globalThis === 'object') return globalThis;
    }
  } else {
    if (typeof globalThis === 'object') return globalThis;
    try {
      return this || new Function('return this')();
    } catch (e) {
      if (typeof window === 'object') return window;
    }
  }
})() as typeof global;

vite users could also always just set window.webpack_require.g = window

@2heal1
Copy link
Copy Markdown
Member

2heal1 commented Nov 4, 2024

how about use document.defaultView https://developer.mozilla.org/en-US/docs/Web/API/Document/defaultView

@2heal1
Copy link
Copy Markdown
Member

2heal1 commented Nov 4, 2024

This attr can help get real window , and no csp problem , for node env , we will use catch globalThis

#3163

how about use document.defaultView https://developer.mozilla.org/en-US/docs/Web/API/Document/defaultView

@ScriptedAlchemy
Copy link
Copy Markdown
Member

This attr can help get real window , and no csp problem , for node env , we will use catch globalThis

#3163

how about use document.defaultView https://developer.mozilla.org/en-US/docs/Web/API/Document/defaultView

Nice find

@danhorvath
Copy link
Copy Markdown
Author

Got fixed in #3163 - thanks for the help!

@danhorvath danhorvath closed this Nov 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Content Security Policy unsafe-eval violation in runtime

5 participants