Closed Bug 1661174 Opened 4 years ago Closed 4 years ago

Verify we are not dereferencing WebShare URLs

Categories

(Core :: DOM: Navigation, task)

task

Tracking

()

RESOLVED FIXED
Tracking Status
firefox-esr78 --- wontfix
firefox81 --- wontfix
firefox82 --- wontfix
firefox83 --- fixed

People

(Reporter: marcosc, Assigned: marcosc)

Details

(Keywords: sec-audit, Whiteboard: [adv-main83-])

Attachments

(1 file)

From [1]

...Web Share API allows users to share links from the browser via 3rd party applications (e.g. mail and messaging apps). The problem is that file: scheme is allowed and when a website points to such URL unexpected behavior occurs. In case such a link is passed to the navigator.share function an actual file from the user file system is included in the shared message which leads to local file disclosure when a user is sharing it unknowingly. The problem is not very serious as user interaction is required, however it is quite easy to make the shared file invisible to the user. The closest comparison that comes to mind is clickjacking as we try to convince the unsuspecting user to perform some action.

Below are the steps to reproduce the issue:

  1. Visit https://overflow.pl/webshare/poc1.html
  2. Click “Share it with friends!”
  3. Select the method (e.g. mail, messages)
  4. “Send it” or “Share it” (or just inspect what has been attached)
  5. Local /etc/passwd has been sent to the recipient

It would be good to have someone verify that we are not affected by this on Android. That is, we are not extracting the file:// contents and sending that.

Noting that we have a windows implementation too (but not shipped, AFAIK)... we might need a different bug for that, but just putting that here for the record.

[1] https://blog.redteam.pl/2020/08/stealing-local-files-using-safari-web.html

Flags: needinfo?(tigeroakes)
Flags: needinfo?(sarentz)

We should be fine here, we don't have any special code to handle URLs. In fact, they're treated as text and just appended to the message body.

Flags: needinfo?(tigeroakes)

Do we think there is anything actionable here?

Flags: needinfo?(sarentz)

Probably nothing specific on Android, but we are discussing if we need to be more restrictive on the DOM side + spec.

Discussion here:
https://github.com/w3c/web-share/issues/173

We should, at the very least, run the URLs through our CheckMayLoad() checks--or whatever has replaced it. If a web site couldn't navigate to or include a URL as a subresource then it shouldn't be allowed to share it. Minimum bar, prevents non-file:/// urls from sharing file:/// and any page from sharing internal nonsense like chrome: or about: urls.

blob: URLs are also problematic -- any external program won't be able to resolve them, and if we ever have "web-share" targets they won't be accessible to targets that aren't same-origin. But if we allow sharing data at some point in the future, it does make sense for a site to be able to share it's own data, which might happen to be in blob: form for convenience but could be converted to a self-contained data: url.

I'm not sure it makes sense to allow a page to be able to share schemes handled by external apps. Maybe the better approach is to create a short allow-list of "web safe" schemes. Preferably in the spec so it's consistent across browsers.

Assignee: nobody → mcaceres

Restrict to "loadable" URLs. Also exclude blob URLs.

Keywords: sec-audit

If it doesn't stick, someone else might need to take this over from tomorrow 🙏

Backed out Backed out for causing wpt failures in share-url-invalid.https.html

https://hg.mozilla.org/integration/autoland/rev/55d3f8ee3a9ca2d1e0dedeb6489acf1581231901

after it had landed as https://hg.mozilla.org/integration/autoland/rev/a2f86092c968318ed33f79a591bae9fc58fbdd85

Push which ran the failing tests: https://treeherder.mozilla.org/#/jobs?repo=autoland&resultStatus=testfailed%2Cbusted%2Cexception%2Cretry%2Cusercancel%2Crunnable&revision=2056a83136fc3752c5ec217e039b28a1068b6eeb&selectedTaskRun=asLJCqPsTomR37IRoNtVWA.0

Failure log: https://treeherder.mozilla.org/logviewer.html#?job_id=314475885&repo=autoland

TEST-UNEXPECTED-FAIL | /web-share/share-url-invalid.https.html | share() rejects file:// URLs - promise_test: Unhandled rejection with value: object "TypeError: navigator.share is not a function"
etc.

Good luck for the future, Marcos.

Martin, can you find someone to take of the failures and reland it?

Flags: needinfo?(mt)

This triggered also these geckoview failures: https://treeherder.mozilla.org/logviewer.html#?job_id=314476347&repo=autoland

[task 2020-08-31T14:08:45.542Z] 14:08:45 INFO - org.mozilla.geckoview.test | Error in saveAndRestoreState(org.mozilla.geckoview.test.ProgressDelegateTest):
[task 2020-08-31T14:08:45.542Z] 14:08:45 INFO - org.mozilla.geckoview.test | java.lang.AssertionError: Scroll position should match
[task 2020-08-31T14:08:45.542Z] 14:08:45 INFO - org.mozilla.geckoview.test | Expected: a numeric value within <0.5> of <100.0>
[task 2020-08-31T14:08:45.542Z] 14:08:45 INFO - org.mozilla.geckoview.test | but: <0.0> differed by <99.5>

I think that this is down to our windows runners not supporting the necessary hooks for this API (and the new tests not being properly listed). I've a patch up on try for which I'll need to find someone to review.

Flags: needinfo?(mt)

Hi Edgar, can you support Martin here once the patch is up for review?

Flags: needinfo?(echen)

Sure thing, feel free to send the review request to me.

Flags: needinfo?(echen)

This landed:

https://hg.mozilla.org/integration/autoland/rev/697a0ad573c6d605c3fad05d2c819e78012ac10b

And got backed out for PromptDelegateTest failures:

https://hg.mozilla.org/integration/autoland/rev/78015058138ad21efa05bb3e8d86eca200400247

Push with failures: https://treeherder.mozilla.org/#/jobs?repo=autoland&group_state=expanded&searchStr=geckoview-junit&revision=697a0ad573c6d605c3fad05d2c819e78012ac10b
Failure log: https://treeherder.mozilla.org/logviewer.html#?job_id=314937868&repo=autoland

TEST-UNEXPECTED-FAIL | org.mozilla.geckoview.test.PromptDelegateTest.dismissedShareReturnsAbortError | java.lang.AssertionError: Error should be correct
TEST-UNEXPECTED-FAIL | org.mozilla.geckoview.test.PromptDelegateTest.abortedShareReturnsAbortError | java.lang.AssertionError: Error should be correct
TEST-UNEXPECTED-FAIL | org.mozilla.geckoview.test.PromptDelegateTest.failedShareReturnsDataError | java.lang.AssertionError: Error should be correct
TEST-UNEXPECTED-FAIL | org.mozilla.geckoview.test.PromptDelegateTest.shareUrlSucceeds | java.lang.AssertionError: Share must succeed.TypeError: Navigator.share: Share URL https://example.com/ must be either http:// or https://.

Flags: needinfo?(mt)

edgar, I know that I'm now asking more of you for this than you signed on for, but do you have any idea why these tests might be failing? It took me about a week to reach the point where I could run these tests at all but I'm not able to reproduce the test failure that occurs on CI.

I'm running in an emulator on Linux. I tried on Windows, but failed.

Flags: needinfo?(mt) → needinfo?(echen)

(In reply to Sebastian Hengst [:aryx] (needinfo on intermittent or backout) from comment #13)

FAIL org.mozilla.geckoview.test.PromptDelegateTest.shareUrlSucceeds - java.lang.AssertionError: Share must succeed.TypeError: Navigator.share: Share URL https://example.com/ must be either http:// or https://

I think it is failed because the share URL (https://example.com/) and test page are not same-origin, so CheckMayLoad() returns false.
It depends on what is behavior we expect: only share same-origin URL v.s. just check if the share URL is http(s).
Per https://github.com/w3c/web-share/pull/174, It seems the latter one is what we expect? (sorry, I didn't not go through all sepc discussion). If so, then CheckMayLoad is too strict, we could replace it with net::SchemeIsHTTP(URL) || net::SchemeIsHTTPS(URL).
If the former one is what we expect, then we need to modify the test, and perhaps add more.

Flags: needinfo?(echen)

Thanks Edgar, that helps point in the right direction. I think that Dan might have mentioned that we have a process for determining whether we can navigate from A to B. For instance, we prevent some origins from navigating to file:///. I thought - incorrectly - that this was what Marcos was invoking here, but that is clearly not the case. Dan, I don't know where to start looking, do you know the function that you are talking about?

Flags: needinfo?(dveditz)

Argh -- I confused two similar names (imho CheckMayLoad is misnamed since it's really about access (JS/DOM) not loading (network)).

I meant we should use nsIScriptSecurityManager::CheckLoadURIWithPrincipal() (note SSM, not the principal)
https://searchfox.org/mozilla-central/source/caps/nsIScriptSecurityManager.idl#116

Flags: needinfo?(dveditz)

Thanks Dan, I've managed to implement that and the tests pass (so that seems like a win).

Christoph, I'm not familiar enough with the flags on CheckLoadURIWithPrincipal to be confident in the change here. Can you give me a quick sanity check? In particular, should I need to include a javascript:window.alert('hi') share target to test the DISALLOW_SCRIPT flag?

Flags: needinfo?(ckerschb)

(In reply to Martin Thomson [:mt:] from comment #18)

Christoph, I'm not familiar enough with the flags on CheckLoadURIWithPrincipal to be confident in the change here. Can you give me a quick sanity check? In particular, should I need to include a javascript:window.alert('hi') share target to test the DISALLOW_SCRIPT flag?

I left comments in phab, probably we can switch to an allow list based approach entirely. Happy to look it over again.

Flags: needinfo?(ckerschb)

Try build here.

I've opened an issue on the spec that I hope resolves in the right direction. It's easy to change the code to a simple allowlist, but I'd rather not for the reasons stated there.

Assuming that is OK, I'd like one last check please Edgar and Christoph.

Flags: needinfo?(echen)
Flags: needinfo?(ckerschb)

(In reply to Martin Thomson [:mt:] from comment #20)

Assuming that is OK, I'd like one last check please Edgar and Christoph.

Thanks, I r+ the patch in phab assuming you update to the revision you pushed to TRY which looks fine to me. Thanks!

Flags: needinfo?(ckerschb)

(In reply to Martin Thomson [:mt:] from comment #20)

Try build here.

Assuming that is OK, I'd like one last check please Edgar and Christoph.

The patch on try looks good to me. Thanks.

Flags: needinfo?(echen)

Is this worth uplifting to Beta?

Flags: needinfo?(mt)

The pref defaults off, so no real point.

Flags: needinfo?(mt)

I tried to check this issue following the steps from the description and I saw the following:
When I try to share with Chrome, the message is: check out this cute kitten! https://somerandommimagewabesite.com/cat.jpg
4:30
But when I share from Fenix I have: file:///etc/passwd.
Device: Google Pixel 4 XL (Android 11), Latest Nightly 9/29 with GV 83.0.a1.
After the changes do this bug require QA? Are there any steps or something to help me test this issue?
@Daniel can you please help me with this one?

Flags: needinfo?(dveditz)

This fix is in DOM so not surprised that Fenix does not know about the Gecko flag.

Component: Security: Android → DOM: Navigation
OS: Android → All
Product: Fenix → Core
Hardware: x86 → All

I can confirm that Android 20200922094538 responds to the "share" button on the POC. With or without dom.webshare.enabled set, so it appears as though Fenix has a parallel implementation of this API. It doesn't seem to load the file though - at least in the apps that I tried. We might need another bug to track that.

(In reply to Martin Thomson [:mt:] from comment #28)

I can confirm that Android 20200922094538 responds to the "share" button on the POC. With or without dom.webshare.enabled set [...]

My mistake. I didn't reload the page after flipping the pref. And the build ID would seem to indicate that it is older than the fix.

The spec has been updated and now says

If url's scheme is not "http" or "https", return a promise rejected with TypeError.

Correct behavior is now to reject the share() promise. In today's Fenix Nightly I'm still seeing it share the URL text like comment 26, which isn't as terrible as sending the file content but is still wrong. Does Fenix Nightly update Gecko/GeckoView nightly? The API is in Gecko and the promise rejection is based on browser information (like the window principal) -- it shouldn't require Fenix sending it any special information.

Sending the URL text, rather than the file data, is not terrible though.

Flags: needinfo?(dveditz)

Dan, we should be blocking the PoC in Fenix, but I'm still on 20200922094538 despite having received an update (I just downloaded 70+M, so I've no idea what that did). I think that it before this fix landed, so I'm not worried (yet).

Re-checked in the latest Nightly from 19/10 Nightly 201019 05:02 (Build #2015770537)AC: 63.0.20201016221440, acd9d4c70GV: 83.0a1-20201016094031AS: 63.0.0.
Note that when I tap on the share it with friends! nothing happens. I had open in links turned ON. On other browsers, I was able to open it in Gmail.
Also, note that no error or message displayed when trying to open that share.
Is this the intended behavior?

Whiteboard: [adv-main83-]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: