dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22k stars 1.72k forks source link

MAUI BlazorWebView fails to establish WebRTC connection on Android due to insecure host (https://0.0.0.0) #24755

Open steveo555 opened 5 days ago

steveo555 commented 5 days ago

Description

Description: When creating a MAUI Blazor Hybrid app in .NET 8.0 and setting up a WebRTC connection between devices, the getUserMedia function in JavaScript works as expected on iOS and Windows platforms, allowing the video stream to be set up successfully.

However, on Android, the connection fails despite the necessary permissions being requested and assigned to the app. The issue arises because the BlazorWebView on Android requests access to the device through the host https://0.0.0.0, which Android treats as insecure, causing the connection to be blocked.

For multi-platform apps that require messaging and communication, this makes MAUI currently unsuitable on Android. There is no clear way to signal to Android that this is a secure connection, nor is there an option to override the default host when calling from the BlazorWebView.

Why this is a bug: This is not a feature request but a bug because the WebRTC setup works perfectly on iOS and Windows out of the box. WebRTC is a widely used standard, and MAUI needs to support it consistently across all platforms, including Android.

Expected Behavior:

The getUserMedia function should be able to request the device's media securely on Android, just as it does on iOS and Windows. MAUI should either treat the BlazorWebView as secure on Android or provide a way to override the default host (https://0.0.0.0) used in the WebRTC request.

Steps to Reproduce

Steps to Reproduce:

Create a new MAUI Blazor Hybrid app in .NET 8.0. Implement WebRTC using the getUserMedia function in JavaScript. Test the app on iOS, Windows, and Android devices. Observe that the connection works on iOS and Windows but fails on Android due to the insecure host issue. Environment:

.NET version: 8.0 MAUI version: (insert version) Platform: Android (failing), iOS and Windows (working)

Link to public reproduction project repository

No response

Version with bug

8.0.82 SR8.2

Is this a regression from previous behavior?

No, this is something new

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

14 and up

Did you find any workaround?

No workarounds currently work.

Relevant log output

14:03:20:299    [CameraManagerGlobal] Connecting to camera service
14:03:20:299    [VendorTagDescriptor] addVendorDescriptor: vendor tag id 11706189966126095484 added
14:03:20:299    [VendorTagDescriptor] addVendorDescriptor: vendor tag id 15055940602041719656 added
14:03:20:366    [CameraManagerGlobal] Camera 0 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 1 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 2 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 20 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 21 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 23 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 3 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client com.samsung.android.smartface API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 4 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 52 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 56 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [DeviceStateManager] handleDeviceStateInfoChanged state=0, baseState=0
14:03:20:366    [CameraManagerGlobal] Camera 58 facing CAMERA_FACING_BACK state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 71 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 73 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:366    [CameraManagerGlobal] Camera 90 facing CAMERA_FACING_FRONT state now CAMERA_STATE_CLOSED for client android.system API Level 2 User Id 0
14:03:20:422    [chromium] [INFO:CONSOLE(58)] "Error initializing camera: [object DOMException]", source: https://0.0.0.0/js/jsMessage.js (58)
github-actions[bot] commented 5 days ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

steveo555 commented 5 days ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

These are either not the same issue or have poor workarounds that have since been removed by losing access to various overloads.

ninachen03 commented 4 days ago

Could you provide us with a sample project so we can investigate it further? Looking forward to your reply!

steveo555 commented 3 days ago

Please find attached project to test.

Run in Windows mode it will work, deploy to iPhone and it will also work, try deploying to Android phone you will get the error. https://0.0.0.0 is trying to get access to camera and fail.

MAUIBlazorWebRTCTTest.zip

drasticactions commented 1 day ago

@steveo555 How do you know that the use of https://0.0.0.0 is the root issue here?

Running your sample, I looked at that object DOMException and it's a NOT ALLOWED permission error. Your app does request permissions, but that's for the App itself. The webview itself needs to have those permissions set, which should be, I think, done in WebChromeClient (https://github.com/dotnet/maui/blob/b2c1d25f7a71197666c2053c1e40dbdea6049cc7/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs#L15-L98) which isn't happening.

So I think there's a bug here in MAUI with its Blazor Webview, but it seems like a permission error, unrelated to the host. Do you have a way to verify your claim?

steveo555 commented 2 hours ago

Hi Thanks for getting back to me.

@steveo555 How do you know that the use of https://0.0.0.0 is the root issue here?

Running your sample, I looked at that object DOMException and it's a NOT ALLOWED permission error. Your app does request permissions, but that's for the App itself. The webview itself needs to have those permissions set, which should be, I think, done in WebChromeClient (

https://github.com/dotnet/maui/blob/b2c1d25f7a71197666c2053c1e40dbdea6049cc7/src/BlazorWebView/src/Maui/Android/BlazorWebChromeClient.cs#L15-L98

) which isn't happening. So I think there's a bug here in MAUI with its Blazor Webview, but it seems like a permission error, unrelated to the host. Do you have a way to verify your claim?

Thanks for the reply. Did you try adding this to the sample I gave and got it to work? I still get the error. Also I have collated the following....

"Android restricts access to certain web APIs, including those for camera access, to secure origins only."

Source: Chromium Security FAQ

"Certain web platform features are restricted to secure contexts. For example, the geolocation API and the getUserMedia API (for accessing the microphone and camera) are only available to secure origins."

Chromium Security FAQ

Android Developers Documentation "For apps targeting Android 6.0 (API level 23) and later, the system considers your app's activities to be secure by default, and secure origins are required for secure content."

https://developer.android.com/guide/webapps/security

Explanation: Android's WebView is based on Chromium and inherits its security policies. Both platforms restrict access to sensitive APIs like the camera to secure origins to protect user privacy and security.

"This means that web pages must be served over HTTPS with a valid certificate from a recognized Certificate Authority (CA)."

Source: W3C Secure Contexts Specification

"A context is considered secure when it is delivered securely and all the resources it loads are also delivered securely."

https://www.w3.org/TR/secure-contexts/#secure-context

MDN Web Docs on getUserMedia() For security reasons, getUserMedia() can only be used from a secure origin (HTTPS or localhost).

https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

Explanation: Secure origins are typically defined as HTTPS connections using valid SSL/TLS certificates issued by recognized CAs. This ensures encrypted communication and verified server identity.

"Using an insecure origin like https://0.0.0.0 will result in Android refusing permission requests for sensitive features like the camera."

Source: IANA Special-Purpose Address Registry "0.0.0.0/8 — This block denotes invalid or unknown addresses."

IANA IPv4 Special-Purpose Address Registry Let's Encrypt Documentation "Let's Encrypt can't issue certificates for 'localhost' or for IP addresses such as '127.0.0.1'." Let's Encrypt - Certificates for localhost

Explanation: The IP address 0.0.0.0 is non-routable and cannot have a valid SSL/TLS certificate issued to it. As a result, any HTTPS connection to 0.0.0.0 is considered insecure, and Android will deny permission requests from such origins. Additional References:

Google Developers on Secure Contexts:

"Starting with Chrome 47, getUserMedia() (for camera and microphone access) is only available from secure origins." Google Developers - Avoiding the Not Secure Warning in Chrome

Web Fundamentals - What is Considered a Secure Context?

"A context is considered secure when it is delivered securely and all the resources it loads are also delivered securely." Web Fundamentals - Secure Contexts

So from API 23 and above Andriod will also black https://0.0.0.0 from access to the camera.

That's why we need another mechanism to serve pages in the blazorwebview that allows either a certificate or localhost as the host.

Let me know what you think.