Open Bug 886663 Opened 8 years ago Updated 4 years ago

When loading an HTTP bookmarklet in a completely HTTPS page, Mixed Content Blocker won't honor exceptions

Categories

(Firefox :: Security, defect)

defect
Not set
normal

Tracking

()

People

(Reporter: strugee, Unassigned)

References

(Blocks 1 open bug, )

Details

Followup to bug 883692.

STR:
1. Install HTTPS Everywhere (dunno if this is required, but it's in my setup)
2. Install the bookmarklet from http://getpocket.com/add
3. Visit a completely HTTPS website that does not violate Mixed Content Blocker policy, e.g. https://en.wikipedia.org/wiki/Dave_Winer. Notice how it doesn't have the shield icon for a mixed content violation.
4. Click on the bookmarklet. As it's served over HTTP, the shield icon pops up and the bookmarklet is blocked from loading. This is expected.
5. Click on the shield, then the doorhanger arrow, and click "disable protection for this page".
6. Click on the bookmarklet again. It does not load and instead triggers the shield icon again, despite the fact that an exception has been set.

I suspect this behavior is related to the fact that by default, the page doesn't trigger mixed content warnings. But I have no idea if this suspicion is warranted or not.

Reproducible: always.

I'm using today's Nightly (2013-06-24).
(In reply to Alex Jordan [:strugee] from comment #0)

> 1. Install HTTPS Everywhere (dunno if this is required, but it's in my setup)
Can you please be more specified about HTTPS Everywhere? What's this?

> 4. Click on the bookmarklet. As it's served over HTTP, the shield icon pops
> up and the bookmarklet is blocked from loading. This is expected.
I dont understand what do you want to say. Clicking on the bookmarklet does not pop up the shield icon, the bookmarklet contains a simple javascript code and it is run local.
Flags: needinfo?(alexander3223098)
QA Contact: mihai.morar
(In reply to Mihai Morar, QA [:MarioMi] from comment #1)
> (In reply to Alex Jordan [:strugee] from comment #0)
> 
> > 1. Install HTTPS Everywhere (dunno if this is required, but it's in my setup)
> Can you please be more specified about HTTPS Everywhere? What's this?
See https://www.eff.org/https-everywhere/. Basically what it does is whenever you load a page, HTTPS Everywhere looks at a set of rules, and if it can, it rewrites the page and page URLs, etc. to use HTTPS instead of HTTP.

> > 4. Click on the bookmarklet. As it's served over HTTP, the shield icon pops
> > up and the bookmarklet is blocked from loading. This is expected.
> I dont understand what do you want to say. Clicking on the bookmarklet does
> not pop up the shield icon, the bookmarklet contains a simple javascript
> code and it is run local.
Yes, but what it really does is insert a new <script> tag into the page. That script tag then references a remote script that contains the real logic.
This is done all the time with bookmarklets - the reason is because while you can't make sure the user updates their bookmarklet, you have control over the script that eventually gets fetched. The bookmarklet essentially becomes a thin loader for the "real" remote script.
Flags: needinfo?(alexander3223098)
This article explains the issues with bookmarklets, Mixed Content Blocker, and CSP.

There is also a CSP bug on bookmarklets - https://bugzilla.mozilla.org/show_bug.cgi?id=866522
See Also: → 866522
Can you attach the bookmarklet to this bug?
Mixed Content Blocker is invoked per page load.  If you "disable protection" on a page, and then reload it, Mixed Active Content will be disabled again.

This poses a problem for bookmarklets.  Bookmarklets that require HTTP active content loads will not work in FF 23+.  Here is an example:

I created a simple bookmarklet that injects HTTP script into a page:

javascript:(function(){var script=document.createElement('SCRIPT');script.src='http://people.mozilla.com/~tvyas/script.js';document.body.appendChild(script);})()

I add the bookmarklet to my Bookmarks.

I go to https://people.mozilla.com/~tvyas/index.html (or any https page).  I go to my Bookmarks and select the bookmarklet.  I see the shield icon in the address bar.  The webconsole shows that a Mixed Content script was blocked:

Blocked loading mixed active content "http://people.mozilla.com/~tvyas/script.js" @ javascript:(function(){var%20script=document.createElement('SCRIPT');script.src='http://people.mozilla.com/~tvyas/script.js';document.body.appendChild(script);})():1

I click on the shield Icon and I disable protection.  Nothing happens.  I still see the lock icon in the url bar.  (This is because when you "disable protection" you are calling BrowserReload with a flag indicating that mixed content is allowed.  Since there is no mixed content on the page, the security state is still STATE_IS_SECURE and you see the lock icon.)

I click the bookmarklet again.  Again I see the Shield Icon and the webcosnole shows that the Mixed Content script is blocked.
Interestingly, if you use the console instead of a bookmarklet, I experience a different behavior.

* Go to https://people.mozilla.com/~tvyas/index.html (or any https page)
* Open the console
* Enter: javascript:(function(){var script=document.createElement('SCRIPT');script.src='http://people.mozilla.com/~tvyas/script.js';document.body.appendChild(script);})()
* You will see the shield icon doorhanger and a message about the blocked script in the webconsole
* Disable Protection
* Paste the javascript code into the console again.
* The script runs (you get an alert(9)) and the page shows the yellow triangle icon (indicating it is an https page with mixed active content loaded).

Why is the behavior different for the console?
(In reply to Tanvi Vyas [:tanvi] from comment #5)
> This poses a problem for bookmarklets.  Bookmarklets that require HTTP
> active content loads will not work in FF 23+.  

Cc'ing some folks who may have thoughts on this.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Basically, bookmarklets that inject scripts into pages need to be replaced with something that doesn't inject scripts into pages. As they are now, the bookmarklets that inject <script src=http://...> are potentially destroying the security of every page they are used on. We shouldn't facilitate such dangerous behavior.

For the mixed content blocker case, changing the bookmarklet to inject <script src=https://...> will work around the problem. But, all users of the bookmarklet would have to update the bookmarket. That's one of the huge shortcomings of bookmarklets in the first place.

Even an updated bookmarklet that used https: or data: scripts would potentially not work if the site uses CSP, depending on the CSP policy. But, that's a different issue that's already being tracked. Potentially we can provide a secure way around that problem for data:. But, I think most bookmarklets that inject scripts will not be able to switch to data: URIs easily.

Ultimately, the solution is probably to have addon developers switch from bookmarklets to extensions for this kind of functionality. That may mean that we need to make the creation of bookmarklet-like extensions much simpler than it currently is. (Note that, interestingly, MSIE8 went down that route already with their "Accelerator" thing.)
See http://blog.kotowicz.net/2013/07/jealous-of-prism-use-amazon-1-button.html, which describes exactly the type of attack that we're defending against (though that's an extension, not a bookmarklet).
Bookmarklets that introduce Mixed Content should be blocked.  But there should be an option for a user to "disable protection" and re-invoke the bookmarklet.  Disabling protection and reinvoking the bookmarklet doesn't work, and here is why...

(In reply to Tanvi Vyas [:tanvi] from comment #6)
> Why is the behavior different for the console?

When you write script in the webconsole, the script goes through nsContentPolicy::CheckPolicy() which calls nsMixedContentBlocker on the script.  nsMixedContentBlocker checks if Mixed Content Blocking has been disabled on the page load.  It uses the mixedContentChannel to check this information.

When you use a bookmarklet on a webpage, the bookmarklet invokes LoadURI() before the script goes through nsMixedContentBlocker.  LoadURI() calls InternalLoad() which calls DoURILoad().  DoURILoad() looks to see if the load flag to allow mixed content is set (LOAD_RELOAD_ALLOW_MIXED_CONTENT).  This load type was set on the previous load, but not this one load.  This load is the result of trying to invoke a bookmarklet, not "disabling protection".  Since DoURILoad doesn't see the flag for loading mixed content, it sets the mixedContentChannel to null.  When the script in the bookmarklet goes through nsMixedContentBlocker, it blocks the mixed content since the mixedContentChannel is null.

How do we fix this?  Perhaps there is a way to identify a load initiated by a bookmarklet and persist the mixed content channel in that case (not set it to null, just leave it alone).  I don't think the channel will change because of a bookmarklet.  So if there is a way to tell that this load is due to a bookmarklet, I could add that check here: http://mxr.mozilla.org/mozilla-central/source/docshell/base/nsDocShell.cpp#9538
(In reply to Brian Smith (:briansmith), was bsmith@mozilla.com (:bsmith) from comment #8)
> Even an updated bookmarklet that used https: or data: scripts would
> potentially not work if the site uses CSP, depending on the CSP policy. But,
> that's a different issue that's already being tracked. Potentially we can
> provide a secure way around that problem for data:. But, I think most
> bookmarklets that inject scripts will not be able to switch to data: URIs
> easily.
Note that bookmarklets being blocked because of CSP is in violation of the spec: http://www.w3.org/TR/CSP/#processing-model. See bug 866522 (I think this is what you were talking about when you said it was being tracked, but I'm not sure)
(In reply to Alex Jordan [:strugee] from comment #11)
> Note that bookmarklets being blocked because of CSP is in violation of the
> spec: http://www.w3.org/TR/CSP/#processing-model. See bug 866522 (I think
> this is what you were talking about when you said it was being tracked, but
> I'm not sure)

"SHOULD NOT" means "RECOMMENDED" and it does not mean "MUST NOT." So, we're not really violating the spec; we're just not following all its recommendations. That recommendation should just be removed from the spec.; the spec should say something like "A user-agent MAY allow user-supplied scripts such as third-party user-agent add-ons and JavaScript bookmarklets to violate the CSP policy."

Anyway, you are right that bug 866522 is the bug I was referring to.
(In reply to Brian Smith (:briansmith), was bsmith@mozilla.com (:bsmith) from comment #12)
> (In reply to Alex Jordan [:strugee] from comment #11)
> > Note that bookmarklets being blocked because of CSP is in violation of the
> > spec: http://www.w3.org/TR/CSP/#processing-model. See bug 866522 (I think
> > this is what you were talking about when you said it was being tracked, but
> > I'm not sure)
> 
> "SHOULD NOT" means "RECOMMENDED" and it does not mean "MUST NOT." So, we're
> not really violating the spec; we're just not following all its
> recommendations. That recommendation should just be removed from the spec.;
> the spec should say something like "A user-agent MAY allow user-supplied
> scripts such as third-party user-agent add-ons and JavaScript bookmarklets
> to violate the CSP policy."
> 
> Anyway, you are right that bug 866522 is the bug I was referring to.
Ah, okay. I'm not aware of W3C language, so thanks for pointing that out.
Since there isn't really a viable option vs FF for many websites and functions,  this should be a user option and not something mandated by the powers that be.

Some bookmarklets can be edited to use HTTPS, but for those that do not, there should be an option of accepting the risk, even if the user doesn't REALLY know the risk.
I thought the fix to bug 902156 would also fix this issue because it adds persistence to the disable protection option while you are navigating a specific page.  For some reason, it doesn't resolve the issue.  Not sure why.
I have always problem with this bug...
Any news ?
It's difficult to understand this story of CSP...
We should control that easily but it's not.
I hope you find a solution.
 
Why on the Mozilla Addon pages, by example on https://addons.mozilla.org/en-US/firefox/addon/context-search-we/,
 i can't use a bookmarklet which add a bookmark to Blogmarks (http://blogmarks.net/)??

Here the code of the bookmarklet (work perfectly on other sites http or https):

javascript:var%20q='';var%20r='';if(document.selection)q=document.selection.createRange().text;else%20if(window.getSelection)q=window.getSelection();if(document.referrer)r=document.referrer;void(open('http://blogmarks.net/my/marks,new?mini=1'+'&title='+encodeURIComponent(document.title)+'&url='+encodeURIComponent(location.href)+'&summary='+encodeURIComponent(q)+'&via='+encodeURIComponent(r),'blogmarks','location=no,toolbar=no,scrollbars=yes,width=350,height=450,status=no'));
You need to log in before you can comment on or make changes to this bug.