Closed Bug 1328824 Opened 8 years ago Closed 8 years ago

Write a test that about:blocked can load successfully in (mixed-content) frames

Categories

(Core :: DOM: Security, defect, P2)

defect

Tracking

()

RESOLVED FIXED
mozilla53
Tracking Status
firefox53 --- fixed

People

(Reporter: Gijs, Assigned: hchang)

References

Details

(Whiteboard: [domsecurity-active])

Attachments

(1 file)

See bug 1293476 for context. We should ensure that there are tests for the failure in that bug so it doesn't happen again (either due to mixed-content-blocking or due to other changes). Note that bug 1195242 might change things here so that a blocking page appears for the toplevel document (to avoid the blocking being in a hidden frame). Unfortunately solving that is not entirely trivial, because trivially 'promoting' the 'bad' frame from a (potentially hidden) iframe to the toplevel document in order to show the about:blocked page changes the URL in the URL bar to the likely-malicious one, which we don't want. If/when we do fix bug 1195242, the test here should be updated - but we should have a test in the meantime. Henry, can you own writing a test?
Flags: needinfo?(hchang)
Sure I can! So, the test we need for now is to make sure the about:blocked frame can be loaded in the secure context (https). I am wondering if the test case is still needed after fixing Bug 1195242. The entire page will show about:blocked after Bug 1195242 so the top level document is "perceptually" redirected. What does the test case for this bug can do? (there is no iframe to test).
Flags: needinfo?(hchang) → needinfo?(gijskruitbosch+bugs)
(In reply to Henry Chang [:henry][:hchang] from comment #1) > Sure I can! > > So, the test we need for now is to make sure the about:blocked frame can be > loaded in the secure context (https). I am wondering if the test case is > still needed after fixing Bug 1195242. > The entire page will show about:blocked after Bug 1195242 so the top level > document > is "perceptually" redirected. What does the test case for this bug can do? > (there is no > iframe to test). bug 1195242 would require changes to this test. But AFAIK we have no plans right now (how) to fix bug 1195242, and I think we should write a test for the current behaviour.
Flags: needinfo?(gijskruitbosch+bugs)
Assignee: nobody → hchang
I tried to modify the existing MCB test case to test this issue by 1) Create a new iframe which points to "https://itisatrap.org/firefox/its-a-trap.html", which is the hard-coded URL that will be blocked. [1] 2) When a site is blocked, a custom event "AboutBlockedLoaded" will be sent by [2]. 3) If we can catch the "AboutBlockedLoaded" event, then we do know about:blocked is successfully loaded. That's my plan. However, I was struggling catching the event sent from blockedSite.xhtml [2]. To the best of my knowledge, the event is sent inside the iframe so we can't receive it outside if "iframe.src" is cross-origin, which means iframe.addEventListener iframe.contentDocument.addEventListener don't work. The original use of "AboutBlockedLoaded" is in [3], which is not the iframe case. I tried wrapping the iframe with SpecialPowers such as var wrappedIframe = SpecialPowers.wrap(iframe); then do addEventListener. Unfortunately, they didn't work, too :( Francois, Gij, do you have any idea about this? Thanks! [1] https://dxr.mozilla.org/mozilla-central/source/toolkit/components/url-classifier/SafeBrowsing.jsm#333 [2] https://dxr.mozilla.org/mozilla-central/rev/b548da4e16f067e5b69349376e37b2db97983cf7/browser/base/content/blockedSite.xhtml#138 [3] https://dxr.mozilla.org/mozilla-central/rev/b548da4e16f067e5b69349376e37b2db97983cf7/browser/components/safebrowsing/content/test/browser_whitelisted.js#39
Flags: needinfo?(gijskruitbosch+bugs)
Flags: needinfo?(francois)
You may have to add bubbles true to make the event work in iframe var event = new CustomEvent("AboutBlockedLoaded", {bubbles:true});
Use a browser mochitest and in a contenttask, add a listener for the custom event on |this| in the contenttask, then load the frame and you should be able to get this event similar to how content.js does for about:neterror: https://dxr.mozilla.org/mozilla-central/source/browser/base/content/content.js#267
Flags: needinfo?(gijskruitbosch+bugs)
Thanks Thomas and :Gijs! I was also thinking using the browser mochitest as my final solution if I didn't manage to test in normal mochitest. BTW, do you know why we are unable to receive the event sent from the iframe in the normal mochitest even with SpecialPowers? Or is it able to be done but just way much easier in browser mochitest? Thanks!
Flags: needinfo?(gijskruitbosch+bugs)
(In reply to Henry Chang [:henry][:hchang] from comment #6) > BTW, do you know why we are unable to receive the event sent from the iframe > in the normal mochitest even with SpecialPowers? Or is it able to be done > but just way much easier in browser mochitest? I don't know. You'll need to bubble the event either way, though, as Thomas said. I wonder if that'll let the other unprivileged frames see it. I would hope not, but I'm not sure.
Flags: needinfo?(gijskruitbosch+bugs)
Flags: needinfo?(francois)
After one day investigation, my current understanding is: if an event is sent inside the iframe, the event target list, which is constructed at [1], would be (suppose we call dispatchEvent on window.document inside an iframe) 0) nsDocment 1) nsGloblaWindow 2) nsInProcessTabChildGlobal 3) XULElement 4) ... ... ... 18) nsGlobalChromeWindow 19) nsWindowRoot where nsDocument is the source of the event and nsGloblaWindow is iframe.contentWindow. nsInProcessTabChildGlobal is a little tricky. It is obtained in [2], where the |frameElement| is the frame used to load the "top scriptable window" [3] of the iframe.contentWindow. In other words, the iframe inner event will still bubble cross the iframe boundary but only directly jump to the top level window's frame loader owner. It explains why we can only receive the event in the browser level. I was hoping to use SpecialPowers.wrap(window.top.frameElement) .QI(nsIFrameLoaderOwner).frameLoader.ownerElement to addEventListern but it didn't work. Maybe I am still missing something. I may try another day to get the iframe inner event in content mochitest. Will switch to browser chrome test if I failed again ^^" [1] https://dxr.mozilla.org/mozilla-central/rev/d192a99be4b436f2dc839435319f7630d5d8f4b0/dom/events/EventDispatcher.cpp#766 [2] https://dxr.mozilla.org/mozilla-central/rev/d192a99be4b436f2dc839435319f7630d5d8f4b0/dom/base/nsGlobalWindow.cpp#3245 [3] https://dxr.mozilla.org/mozilla-central/rev/d192a99be4b436f2dc839435319f7630d5d8f4b0/dom/base/nsGlobalWindow.cpp#3242
Status: NEW → ASSIGNED
I still failed to obtain (2) (i.e. nsInProcessTabChildGlobal in non-e10s case) in the plain mochitest so I took chrome mochitest. As how it's written in the attached patch, the event listener is added to the top level window frame loader, it can successfully receive the "AboutBlockedLoaded" event.
Priority: -- → P2
Whiteboard: [domsecurity-active]
Attachment #8825357 - Flags: review?(francois)
Attachment #8825357 - Flags: review?(gijskruitbosch+bugs)
Hi Gijs, francois, I think you both will be interested in reviewing this patch. After a million failures of writing this test in plain mochitest, I decided to use a chrome mochitest and open up a browser, use ContentTask.spawn to inject frame script to do the test so it works very well. However, the try result shows the test case still suffers from non-local network request. I don't know the root cause yet (I have turned off the report actually) but it shouldn't be tough to fix.
Flags: needinfo?(gijskruitbosch+bugs)
Comment on attachment 8825357 [details] Bug 1328824 - Test if about:blocked can be loaded in a secure context. https://reviewboard.mozilla.org/r/103518/#review104554 ::: toolkit/components/url-classifier/tests/mochitest/chrome.ini:27 (Diff revision 1) > [test_trackingprotection_whitelist.html] > tags = trackingprotection > [test_safebrowsing_bug1272239.html] > [test_donottrack.html] > [test_classifier_changetablepref.html] > +[test_mcb_meets_safebrowsing.html] Our naming of tests is very unfortunate. I meant a browser mochitest: https://developer.mozilla.org/en-US/docs/Mozilla/Browser_chrome_tests . You've written a chrome test, but those only run in non-e10s (because XUL in the content process isn't really something we want to support, AIUI). So now we'll never be testing this in e10s. It should not be hard to write this as a browser mochitest instead - you mostly will get rid of the HTML boilerplate, and you won't need to open a new window and can just create a new tab instead.
Attachment #8825357 - Flags: review?(gijskruitbosch+bugs) → review-
Flags: needinfo?(gijskruitbosch+bugs)
Attachment #8825357 - Flags: review?(francois)
Finally done the browser mochitest test case! In order to avoid hitting non-local network, I had to redirect https://itisatrap.org to localhost. ("http://itisatrap.org" has been done so because it's being used in other test cases.)
Comment on attachment 8825357 [details] Bug 1328824 - Test if about:blocked can be loaded in a secure context. https://reviewboard.mozilla.org/r/103518/#review105200 This looks pretty good. I have some suggestions to tidy it up a bit. See below. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:9 (Diff revision 2) > +let tabbrowser = null; > + > +registerCleanupFunction(function() { > + tabbrowser = null; > + while (gBrowser.tabs.length > 1) { > + gBrowser.removeCurrentTab(); > + } > +}); You don't need this, and it might remove the wrong tab. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:21 (Diff revision 2) > + let observerService = Cc["@mozilla.org/observer-service;1"] > + .getService(Ci.nsIObserverService); You can use `Services.obs` throughout. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:33 (Diff revision 2) > + observerService.addObserver(function() { > + ok(true, "Received internal event!"); > + callbackOnce(); > + }, "mozentries-update-finished", false); This will keep this observer forever and might cause leaks. Please ensure removeObserver is called in callbackOnce. You'll probably need to put the observer function in a local variable so you can reference it. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:45 (Diff revision 2) > + let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"] > + .getService(Ci.nsIScriptSecurityManager); > + let iosvc = Cc["@mozilla.org/network/io-service;1"] > + .getService(Ci.nsIIOService); Services.scriptSecurityManager and Services.io, respectively. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:54 (Diff revision 2) > + QueryInterface: function(iid) > + { Nit: brace on same line, here and for the other method. Nit: just use: ```js XPCOMUtils.generateQI([Ci.nsIUrlClassifierUpdateObserver]) ``` to get a QI method. You don't need to add Ci.nsISupports in the array you pass it. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:56 (Diff revision 2) > + if (iid.equals(Ci.nsISupports) || > + iid.equals(Ci.nsIUrlClassifierUpdateObserver)) Nit: indentation. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:71 (Diff revision 2) > + let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"] > + .getService(Ci.nsIUrlClassifierDBService); Nit: indentation. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:77 (Diff revision 2) > + tabbrowser = gBrowser; > + let tab = tabbrowser.selectedTab = tabbrowser.addTab(); > + let testingBrowser = tab.linkedBrowser; > + > + // Load an secure conatiner page. > + yield BrowserTestUtils.loadURI(testingBrowser, SECURE_CONTAINER_URL); > + yield BrowserTestUtils.browserLoaded(testingBrowser); Instead of these lines, use: ```js let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, SECURE_CONTAINER_URL); let testingBrowser = tab.linkedBrowser; ``` and then add the end: ```js yield BrowserTestUtils.removeTab(tab); ``` Alternatively, you can use the `withNewTab` wrapper that takes a generator function and takes care of opening and closing the tab for you: ```js add_task(function* testNormalBrowsing() { yield BrowserTestUtils.withNewTab(SECURE_CONTAINER_URL, function* (browser) { // 'browser' is now a reference to the tab's linkedBrowser that you can use with ContentTask.spawn. }); ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:81 (Diff revision 2) > +add_task(function* testNormalBrowsing() { > + tabbrowser = gBrowser; > + let tab = tabbrowser.selectedTab = tabbrowser.addTab(); > + let testingBrowser = tab.linkedBrowser; > + > + // Load an secure conatiner page. If the comment stays: nit: spelling 'container'. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:98 (Diff revision 2) > + removeEventListener('AboutBlockedLoaded', listener, false, true); > + resolve(); > + }; > + addEventListener('AboutBlockedLoaded', listener, false, true); > + > + // Create an iframw which loads a phish url. Nit: spelling 'iframe'
Attachment #8825357 - Flags: review?(gijskruitbosch+bugs)
Hi :Gijs, Thanks for your review and suggestions! They are all very helpful. Sorry for my unfamiliarity with browser chrome test. The new patch is addressed all comments from the previous review. Could you please review again? Thanks!
Comment on attachment 8825357 [details] Bug 1328824 - Test if about:blocked can be loaded in a secure context. https://reviewboard.mozilla.org/r/103518/#review105656 Two points below, but with that, r=me ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:39 (Diff revisions 2 - 3) > - const table = "test-phish-simple"; > - > + let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"] > + .getService(Ci.nsIUrlClassifierDBService); Indenting is still odd here. Either 2-space indent from the start of the previous line, or align the '.' with the '[' on the previous line. ::: browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:49 (Diff revisions 2 - 3) > callbackOnce(); > } > }, > - }; > > - let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"] > + QueryInterface: XPCOMUtils.generateQI([Ci.nsIUrlClassifierUpdateObserver]) Huh, this is actually wrong (which I assume is wrong in the place you copied it from!) - you're writing a nsIUrlClassifierCallback, not an nsIUrlClassifierUpdateObserver (which doesn't have a handleEvent method). See https://dxr.mozilla.org/mozilla-central/source/toolkit/components/url-classifier/nsIUrlClassifierDBService.idl#79-81 Happily, the nsIUrlClassifierCallback interface has the `function` keyword so you don't need an object at all. So just do: ```js dbService.lookup(principal, PHISH_TABLE, value => { if (value == PHISH_TABLE) { ok(true, "DB lookup success!"); callbackOnce(); } }); ```
Attachment #8825357 - Flags: review?(gijskruitbosch+bugs) → review+
Try result: https://treeherder.mozilla.org/#/jobs?repo=try&revision=82da0280021f518c1f79542f7cdddd3f6470f967&selectedJob=69460447 The test case is still suffered from the following error [1]: ////////////// FATAL ERROR: Non-local network connections are disabled and a connection attempt to itisatrap.org (63.245.213.12) was made. ////////////// However, I have added "https://itisatrao.org:443" to server-locations.txt [2]. I am pretty sure "https://itisatrao.org:443" is redirected when I run the test case locally. [1] https://public-artifacts.taskcluster.net/T25cIKsHTlOUr4VOLdNehw/0/public/logs/live_backing.log [2] https://hg.mozilla.org/try/rev/349b0260c8d872480518ee7f8317f2b649d1166d#l5.34
(In reply to Henry Chang [:henry][:hchang] from comment #20) > Try result: > > https://treeherder.mozilla.org/#/ > jobs?repo=try&revision=82da0280021f518c1f79542f7cdddd3f6470f967&selectedJob=6 > 9460447 > > The test case is still suffered from the following error [1]: > > ////////////// > FATAL ERROR: Non-local network connections are disabled and a connection > attempt to itisatrap.org (63.245.213.12) was made. > ////////////// > > However, I have added "https://itisatrao.org:443" to server-locations.txt > [2]. I am pretty sure > "https://itisatrao.org:443" is redirected when I run the test case locally. > > > > > [1] > https://public-artifacts.taskcluster.net/T25cIKsHTlOUr4VOLdNehw/0/public/ > logs/live_backing.log > [2] > https://hg.mozilla.org/try/rev/349b0260c8d872480518ee7f8317f2b649d1166d#l5.34 I wasted a lot of time on this until Ted helpfully pointed out that your server-locations entry has "www." and your test URL does not. Add "www." to PHISH_URL in the test and the problem goes away. If I remove the fix, I can reproduce this locally when using --run-until-failure with the mochitest invocation for this specific testfile. You should be able to verify that change locally that way and then push to autoland.
(In reply to :Gijs from comment #21) > (In reply to Henry Chang [:henry][:hchang] from comment #20) > > Try result: > > > > https://treeherder.mozilla.org/#/ > > jobs?repo=try&revision=82da0280021f518c1f79542f7cdddd3f6470f967&selectedJob=6 > > 9460447 > > > > The test case is still suffered from the following error [1]: > > > > ////////////// > > FATAL ERROR: Non-local network connections are disabled and a connection > > attempt to itisatrap.org (63.245.213.12) was made. > > ////////////// > > > > However, I have added "https://itisatrao.org:443" to server-locations.txt > > [2]. I am pretty sure > > "https://itisatrao.org:443" is redirected when I run the test case locally. > > > > > > > > > > [1] > > https://public-artifacts.taskcluster.net/T25cIKsHTlOUr4VOLdNehw/0/public/ > > logs/live_backing.log > > [2] > > https://hg.mozilla.org/try/rev/349b0260c8d872480518ee7f8317f2b649d1166d#l5.34 > > I wasted a lot of time on this until Ted helpfully pointed out that your > server-locations entry has "www." and your test URL does not. Add "www." to > PHISH_URL in the test and the problem goes away. > > If I remove the fix, I can reproduce this locally when using > --run-until-failure with the mochitest invocation for this specific > testfile. You should be able to verify that change locally that way and then > push to autoland. Oh my god how stupid I am :( Really thank you and Ted! I am almost gonna blame that the try server is caching old server location :p I believe I can finally land this case tomorrow!
Sadly I've got another lint error [1][2] for the following line yield new Promise(resolve => waitForDBInit(resolve)); After a long while try-and-error, I finally found it's just because "yield" is called in a non-generating function. Already fixed it and I will definitely land it today! [1] https://public-artifacts.taskcluster.net/a3XHdFVFQZKy1hnrhDrsMw/0/public/logs/live_backing.log [2] [task 2017-01-18T02:06:50.449416Z] TEST-UNEXPECTED-ERROR | /home/worker/checkouts/gecko/browser/components/safebrowsing/content/test/browser_mixedcontent_aboutblocked.js:54:11 | Parsing error: Unexpected token new (eslint)
Pushed by hchang@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/10f82a72aa02 Test if about:blocked can be loaded in a secure context. r=Gijs
Flags: needinfo?(hchang)
Backout by ihsiao@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/b84c8830194f Backed out changeset 10f82a72aa02 for eslint failure
I wonder why try build eslint test didn't complain those errors. Neither from my local eslint test. :Gijs, do you have any idea that why try server uses maybe different eslint config from other taskcluster machine uses?
Flags: needinfo?(hchang) → needinfo?(gijskruitbosch+bugs)
That rule change landed very recently (bug 1331661). I'd bet your Try push was just on top of a parent that was prior to it landing.
Thanks Ryan! Have fixed it and pushed to mi :)
Flags: needinfo?(gijskruitbosch+bugs)
No problem, thanks for taking this on!
(In reply to Henry Chang [:henry][:hchang] from comment #31) > Thanks Ryan! Have fixed it and pushed to mi :) For some reason no pulsebot: https://hg.mozilla.org/integration/mozilla-inbound/rev/1b83bc5087ec7dbd464ac5a1c0efd2f9b7e1b89d
Status: ASSIGNED → RESOLVED
Closed: 8 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla53
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: