Bug 179220

Summary: mediaDevices.enumerateDevices(), device ids change on page refresh
Product: WebKit Reporter: Chad Phillips <webkit>
Component: WebRTCAssignee: Nobody <webkit-unassigned>
Status: RESOLVED CONFIGURATION CHANGED    
Severity: Normal CC: eric.carlson, jake, jonlee, matthias.rauch, philipp.weissensteiner, webkit-bug-importer, youennf
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Mac   
OS: macOS 10.12   
Attachments:
Description Flags
Test case #1 none

Description Chad Phillips 2017-11-02 17:37:18 PDT
I've used the following Javascript as a test on Firefox, Chrome, and Safari:

      var constraints = {
        audio: false,
        video: true,
      };
      navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
        navigator.mediaDevices.enumerateDevices().then(function(devices) {
          devices.forEach(function(device) {
            console.log(device.kind + ": " + device.label + " id = " + device.deviceId);
          });
        });
      }).catch(function(err) {
        console.error("Device access checks failed: ", err, constraints);
      });

Both Firefox and Chrome preserve device ids across page refreshes (further testing with Chrome shows they are preserved even across machine reboots).

However, Safari does not preserve the device ids at all -- they are completely different across page refreshes.

This is problematic, as it makes it much more difficult for applications to 'remember' which devices a user prefers, having to fall back to matching on device.label, which isn't fully reliable.

Confirmed this issue still exists as of r224308.
Comment 1 philipp.weissensteiner 2017-11-09 09:12:20 PST
I can reproduce this on the iOS (11.1) but it seems to be working as expected on macOS.
Running Version 11.0.1 (12604.3.5.1.1).
Comment 2 Chad Phillips 2017-11-10 16:54:58 PST
@philipp, I can replicate the issue on latest stable desktop Safari for OS X Sierra (Version 11.0.1 (12604.3.5.1.1)), and also on latest Webkit build (r224711) on Sierra, so I don't think the desktop version is working properly.
Comment 3 Chad Phillips 2017-11-10 16:56:46 PST
Created attachment 326661 [details]
Test case #1

Here's a fully working test case which illustrates the issue.
Comment 4 philipp.weissensteiner 2017-11-14 01:08:16 PST
My bad. Yes I can also reproduce it the desktop version of Safari.
Comment 5 Radar WebKit Bug Importer 2017-11-27 08:58:04 PST
<rdar://problem/35698762>
Comment 6 youenn fablet 2017-11-27 09:16:42 PST
These ids are very close to cookies and some restrictions have been put in place to ensure privacy.
We can try to relax some constraints but we should be very cautious here.

Can you detail how you are using these ids? Is it as part of getUserMedia constraints?
Comment 7 Chad Phillips 2017-11-27 10:43:57 PST
The use case is quite simple: device IDs are stored (in my app, in browser localstorage) so they can be passed to gUM requests, such that a specific device is used.

This allows an app to 'remember' a user's preference for camera/mic/speakers across visits. This is particularly important in two cases:

 1. The user has an additional hardware camera that they prefer to use as their camera for the app in question.

 2. Some multi-camera devices (most notably Microsoft Surface) have the rear-facing camera as its default, and no easy way in the device settings to change that. Therefore it falls on the app to provide a decent default user experience.

To quote from https://webkit.org/blog/7763/a-closer-look-into-webrtc/

"navigator.mediaDevices.enumerateDevices exposes the list of capture devices available, and can be queried by websites even when access to those devices is not granted. For users that have custom camera and microphone setups, this can add to a user’s fingerprinting surface. When access hasn’t yet been requested or is explicitly denied, WebKit avoids exposing this additional information by returning a default list of devices that may not correspond to the actual set of devices available."

From a security perspective, it makes perfect sense that dummy/random device IDs would be provided prior to a user granting device access. This makes much less sense once the user has granted access -- especially in the examples above, it makes for a worse experience for the user and the developer.
Comment 8 youenn fablet 2017-12-01 10:16:59 PST
I wonder whether we could not provide the functionality you want without the fingerprinting issue.

Would it be fine if:
- WebKit stores persistently which capture devices were last selected by a web site, at least if changed from the default selected ones.
- Reuse those devices for subsequent selections

That way, you would probably get what you want without having to handle device ids.
If you do not get what you want, you might be able to use label/kind attributes after getting camera/microphone access to further refine selection.
Comment 9 Chad Phillips 2017-12-20 15:33:32 PST
@youenn, that sounds awfully complicated.

How would I, in Javascript, know that Safari has 'remembered' a device, and that device matches the one selected by a user?

This also creates a split between Safari handling the picking of the device, and my own code having to maybe, sometimes, handle it. I think it would be cleaner if the developer always did it, and in this case, the most accurate way to always pick the right device is a reliable machine ID.

I've already built code that looks up the previous device based on the device label, and it's an OK workaround for now, but definitely not as accurate or reliable as a machine ID.

If we can't have consistent IDs, I'd favor what I'm doing now over what you're suggesting.
Comment 10 youenn fablet 2017-12-20 15:40:34 PST
(In reply to Chad Phillips from comment #9)
> @youenn, that sounds awfully complicated.
> 
> How would I, in Javascript, know that Safari has 'remembered' a device, and
> that device matches the one selected by a user?
> 
> This also creates a split between Safari handling the picking of the device,
> and my own code having to maybe, sometimes, handle it. I think it would be
> cleaner if the developer always did it, and in this case, the most accurate
> way to always pick the right device is a reliable machine ID.
> 
> I've already built code that looks up the previous device based on the
> device label, and it's an OK workaround for now, but definitely not as
> accurate or reliable as a machine ID.
> 
> If we can't have consistent IDs, I'd favor what I'm doing now over what
> you're suggesting.

Good to hear the label workaround is working fine.

What I am proposing should allow the browser to do what your application is doing right now.
When in Safari, you would disable the automatic device selection and would only implement explicit user device selection.
If it does not work as is, I agree we should not bother implementing it.
Comment 11 Jake 2020-02-11 20:38:38 PST
What is the status of this?
I can't reproduce this on Safari 13.0.4 and the last comment was over two years ago.
It seems other browsers are taking the approach of treating deviceId like cookies and persisting until the user clears.
Should this bug be marked as resolved?
Comment 12 youenn fablet 2020-02-12 06:38:19 PST
Right, this is now fixed.
Device ids should persist but be available after a getUserMedia successful call in usual cases.