metamask-extension icon indicating copy to clipboard operation
metamask-extension copied to clipboard

Inpage injection fails in Firefox under some CSP settings

Open marcusmolchany opened this issue 7 years ago • 62 comments

Hey, as far as I can tell, my content security policy is preventing MetaMask from injecting its scripts. This is only happening in Firefox. It works correctly in Chrome, Safari, Opera, and Brave. My script-src directive looks like this:

script-src 'self';

and I'm seeing this csp violation in the js console:

Content Security Policy: The page’s settings blocked the loading of a resource at self. Source: (function e(t,n,r){function s(o,u){if(!n ....

Unfortunately Firefox only shows a preview of the blocked script. I've tried sha256 hashing each of the scripts in the latest Metamask release and adding them to the CSP, but that did not work. If you have any ideas that would be great!

Browser: Firefox 58.0.1 Operating System: Mac OSX 10.13.2

marcusmolchany avatar Jan 30 '18 02:01 marcusmolchany

This issue now has a funding of 0.105 ETH (96.44 USD) attached to it.

  • If you would like to work on this issue you can claim it here.
  • If you've completed this issue and want to claim the bounty you can do so here
  • Questions? Get help on the Gitcoin Slack
  • $9607.34 more Funded OSS Work Available at: https://gitcoin.co/explorer

gitcoinbot avatar Feb 15 '18 02:02 gitcoinbot

I've added funding to this issue. I'd love for my site to work on FireFox with MetaMask without having to change my CSP. Thanks!

marcusmolchany avatar Feb 15 '18 02:02 marcusmolchany

I think I can fix this issue, but want to verify that my approach would be correct one.

So the problem is that CSP won't allow inline script that is used here https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/contentscript.js#L30. There's manifest.json property web_accessible_resources that seems to allow injecting scripts that are specified there, but it's only applied if script is loaded with src, not with textContent.

I've tried quickly and replacing scriptTag.textContent = [script_content] with scriptTag.src = [script_url] seems to resolve issue with CSP in Firefox. If this approach is ok, I'll proceed with implementation.

evgeniuz avatar Feb 15 '18 15:02 evgeniuz

Ok, this might be trickier than I expected. I see that loading with src caused race condition in the past, going to look more closely into this.

evgeniuz avatar Feb 15 '18 15:02 evgeniuz

thank you for starting @evgeniuz! I can set up an example application that uses my current CSP if that would help.

marcusmolchany avatar Feb 15 '18 17:02 marcusmolchany

Sorry, but it seems that those two issues are inherently conflicting: when using scriptTag.src there seems to be no way to ensure that script will load before all other scripts and using scriptTag.textContent is disallowed by CSP.

I've noticed that you've tried to use hash to whitelist the script for inline, the file to hash is scripts/inpage.js, but the problem is that sourceURL comment is added here: https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/contentscript.js#L12. Since this sourceURL depends on extension ID, it may be different for each installation, so you cannot whitelist it reliably.

Removing sourceURL from final build will allow to generate hash reliably, so you can whitelist it in CSP. And it can still be added in development build for easier debugging. But I cannot make this decision myself, need some input from Metamask team: is it ok to remove sourceURL suffix in that line so that inline script is same on every installation and can be hashed and whitelisted in CSP?

Going to unassign myself from bounty, as I cannot find another solution at the moment.

evgeniuz avatar Feb 20 '18 15:02 evgeniuz

@evgeniuz thank you very much for all the help here.

marcusmolchany avatar Feb 20 '18 18:02 marcusmolchany

@marcusmolchany would you mind setting up a sample application? I'd like to play with setting up a workaround...

dmihal avatar Mar 02 '18 05:03 dmihal

Hey @dmihal here is a sample application. If you open it in chrome, you should see that web3 is injected into window.web3. If you open it using firefox, you should see that the CSP blocks web3 from being injected.

Here is the repo for the sample application. And this specifically is the CSP.

marcusmolchany avatar Mar 02 '18 07:03 marcusmolchany

@dmihal Would you like to give this one a go? Feel free to claim it on Gitcoin by clicking 'Start Work', if so!

vs77bb avatar Mar 06 '18 23:03 vs77bb

Is this still an issue? MetaMask seems to be working fine on FF for me.

KennethAshley avatar Mar 08 '18 22:03 KennethAshley

Hey @KennethAshley, this is only an issue if you have a Content Security Policy. Does MetaMask successfully inject web3 on my sample application when you use Firefox?

marcusmolchany avatar Mar 09 '18 03:03 marcusmolchany

This is a known bug in firefox. https://bugzilla.mozilla.org/show_bug.cgi?id=1267027. Comment on that issue to get it fixed soon. :)

skkiran-pro avatar Mar 19 '18 09:03 skkiran-pro

@dmxsf1 are you still working on this issue?

gitcoinbot avatar Apr 19 '18 16:04 gitcoinbot

@dmxsf1 are you still working on this issue?

gitcoinbot avatar Apr 22 '18 16:04 gitcoinbot

@dmxsf1 are you still working on this issue?

gitcoinbot avatar Apr 25 '18 16:04 gitcoinbot

@amitkumar991 Hello from Gitcoin Core - are you still working on this issue? Please submit a WIP PR or comment back within the next 3 days or you will be removed from this ticket and it will be returned to an ‘Open’ status. Please let us know if you have questions!

  • [x] warning (3 days)
  • [ ] escalation to mods (6 days)

Funders only: Snooze warnings for 1 day | 3 days | 5 days | 10 days | 100 days

gitcoinbot avatar May 14 '18 16:05 gitcoinbot

Any update? Is this fixed in newer versions of Firefox or Metamask?

filips123 avatar Nov 26 '18 14:11 filips123

Could this be fixed by Metamask or it should be reported to Firefox bugzilla? This should be fixed because many websites don't work because of that.

filips123 avatar Jan 11 '19 17:01 filips123

I believe the "correct" long term solution here is for dapps to change the way they interact with browser signers to better align with the official browser recommendation for pages and extensions communicating, which is via postMessage. I'm currently working on a solution to this, but it will be a big change that will require both dapp and extension buy-in and likely will be very slow to gain adoption.

I wanted to drop a comment here just to make people aware of the potential futures, but at the moment I don't believe there is a great solution. If I am successful, my hope is to get this new mechanism implemented in MetaMask eventually (likely side-by-side with the existing injection technique) and then from there we will try to get dapps to adopt this technique over time.

MicahZoltu avatar Nov 01 '19 09:11 MicahZoltu

try to get dapps to adopt this technique over time.

Does it mean extending the Web3 protocol? (if that's correct to call that a protocol)

tuxayo avatar Nov 05 '19 11:11 tuxayo

It means changing the way dapps communicate with "web3 enabled browsers". Rather than calling functions that were attached to window.ethereum, instead fire and listen for events.

MicahZoltu avatar Nov 05 '19 12:11 MicahZoltu

Hey guys, seems this issue is very old problem, but probably there doesn't exist even hotfix for this issue yet ?

So there is currently no way to use Metamask in Firefox ? (edit: with CSP enabled)

Going to follow also this thread https://bugzilla.mozilla.org/show_bug.cgi?id=1267027 but it also seems to be there for 4 years, so we should probably not expect this to be fixed anytime soon.

As I understand, to fix Metamask in FF, there would be need to change it's communication protocol to postMessages? Is that something what is planned?

jurosh avatar Apr 20 '20 12:04 jurosh

I use MetaMask on Firefox and it seems to work, though I think I'm on a pretty old version at the moment. What page are you unable to use? Is it served via HTTP or HTTPS?

MicahZoltu avatar Apr 20 '20 12:04 MicahZoltu

I use MetaMask on Firefox and it seems to work, though I think I'm on a pretty old version at the moment. What page are you unable to use? Is it served via HTTP or HTTPS?

Both, I was testing on localhost:3000 (http) and also live site with https. Tested with nightly FF (v77) and stable v75.

There is error regarding blocked contentscript.js: Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).

And there is no window.web3 neither ethereum included.

Edit: Without enabled CSP it works. But we cannot turn that off and reduce web security.

jurosh avatar Apr 20 '20 12:04 jurosh

It was failing only if there is a CSP specified on the page (via meta tag or response header). I have not tested it recently.

skkiran-pro avatar Apr 20 '20 12:04 skkiran-pro

https://dai-hrd.keydonix.com works for me in Firefox 75.0 with MetaMask 7.7.8. I am able to click the connect button in the middle of the page, which pops up a MM prompt, and upon accepting I can interact with the UI. I get one error in my console which is from the Uniswap iframe in the page, not from MetaMask.

MicahZoltu avatar Apr 20 '20 12:04 MicahZoltu

https://dai-hrd.keydonix.com works for me in Firefox 75.0 with MetaMask 7.7.8. I am able to click the connect button in the middle of the page, which pops up a MM prompt, and upon accepting I can interact with the UI. I get one error in my console which is from the Uniswap iframe in the page, not from MetaMask.

Yep, works for me too, but that site seems not to use CSP feature.

jurosh avatar Apr 20 '20 13:04 jurosh

There is a possible workaround for pages with a CSP that disallows metamask injection. If the dapp includes the equivalent of our inpage.js bundle, the dapp should be able to talk to metamask. The inpage.js bundle is rarely updated. Until this usecase/limitation is identified to be more common, we won't officially support this but it will work. You can use the inpage.js bundle as is or you can build your own with these parts: https://github.com/MetaMask/metamask-extension/blob/d908102636b6e55b6cbcf592d2d99e727b1b278f/app/scripts/inpage.js#L36-L70

kumavis avatar Apr 21 '20 02:04 kumavis

There is a possible workaround for pages with a CSP that disallows metamask injection. If the dapp includes the equivalent of our inpage.js bundle, the dapp should be able to talk to metamask. The inpage.js bundle is rarely updated. Until this usecase/limitation is identified to be more common, we won't officially support this but it will work. You can use the inpage.js bundle as is or you can build your own with these parts:

Thanks @kumavis , seems this code HOT-fixed MM issue.

(function() {
  if (
     !window.ethereum &&
     !window.web3 &&
     navigator.userAgent.includes('Firefox')
   ) {
     const script = document.createElement('script');
     script.src = '/inpage-metamask.js';
     script.type = 'text/javascript';
     document.getElementsByTagName('head')[0].appendChild(script);
   }
})();

I took inpage.js directly from archive of latest extension from Firefox store.

Also I will keep eye on this topic, so in case there is proper solution I can get rid of this temporary hot-fix.

jurosh avatar Apr 21 '20 10:04 jurosh