Skip to content

added WebRTC Test based on an uninitialized iFrame #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

zphrs
Copy link

@zphrs zphrs commented Jul 14, 2025

This test is specifically designed to get the RTCPeerConnection object before the injected script on android is run. The script injected into Android's WebView from Tauri only runs once the page is loaded, compared to other targets where the injected script is run immediately after the iframe is constructed, before yeilding back to the JS on the parent page which created the iframe.

Here's a simplified exploit:

document.body.innerHTML += "<iframe id=i></iframe>" 
// new window without the WebRTC override
const iframeNotInitedWindow = i.contentWindow; 
// reference to the original peer connection object 
const newRTC = iframeNotInitedWindow.RTCPeerConnection;

While one might think that it is possible to address this by always triggering the override on any write to innerHTML, there are many, many ways to add an iframe to a document to the point where patching all of the holes is virtually (or possibly completely) impossible. For a failed attempt at patching all of the methods possible to insert an iframe without running a script before yielding back to the script which created the iframe, see https://github.com/lavamoat/snow.

This can be mitigated by injecting Fill500 into every document on Android which while not ideal, is a reasonable mitigation for Android specifically.

This test is specifically designed to get the RTCPeerConnection object
before the injected script on android is run. The script injected into
Android's WebView from Tauri only runs once the page is loaded, compared
to other targets where the injected script is run immediately after the
iframe is constructed, before yeilding back to the JS on the parent page
which created the iframe.

Here's a simplified exploit:

document.body.innerHTML += "<iframe id=i></iframe>"
// new window without the WebRTC override
const iframeNotInitedWindow = i.contentWindow.window;
// reference to the original peer connection object
const newRTC = iframeNotInitedWindow.RTCPeerConnection;

While one might think that it is possible to address this by
always triggering the override on any write to innerHTML,
there are many, many ways to add an iframe to a document to the point where
patching all of the holes is virtually (or possibly completely) impossible.
For a
[failed attempt](LavaMoat/snow#158 (comment))
at patching all of the methods possible to insert an iframe without
running a script before yielding back to the script which created the
iframe, see https://github.com/lavamoat/snow.

This can be mitigated by injecting Fill500 into every frame which while
not ideal, is a reasonable mitigation for Android specifically.
Copy link
Member

@WofWca WofWca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot! This makes sense.

I have checked that this test still passes on Android and Desktop Electron and Tauri.

CC @Simon-Laux because your recently worked on this, so you might be interested.

@WofWca WofWca added the enhancement New feature or request label Jul 15, 2025
@Simon-Laux
Copy link
Contributor

Simon-Laux commented Jul 15, 2025

CC @Simon-Laux because your recently worked on this, so you might be interested.

not sure if FILL500 in every frame is the right way as I'm not sure how the connections are shared, atleast they are shared on dc-android (not tauri) - there we run fill500 before loading the app into an iframe.

Recently I tried to get rid of fill500, by copying the tauri method for injecting scripts, sadly it's not the same api as in windows, so it failed to secure some special pages such as about:blank: deltachat/deltachat-android#3797

At this point I think we either need to ship our own custom web-view or push some effort to implement the webrtc: block CSP directive into browsers, in this case specifically into chromium.

Regardless much thanks for the extra test, more tests are always appreciated.

@zphrs
Copy link
Author

zphrs commented Jul 15, 2025

My test passes in my sandbox which uses Fill500 only on Android, but my sandbox also does not support navigation as of yet; I don't know if navigation creates a new process.

I do know however that any iframes which are accessible by the parent (sandbox="allow-same-origin", about:blank frames such as the one I create in this PR, or just a normal unsandboxed same-origin iframe) are currently running on the same thread in all modern browsers. While no spec guarantees this, it would be immensely difficult to spin off same-origin iframes onto their own thread because you'd have to support cross-thread references to HTML elements. While technically possible, performance would suffer greatly and it would require a major refactor of how DOM references work to allow the references to be passed between threads.

Compared to that major refactor, I think it is much more likely that chrome simply removes their 500 connection limit and so I still immensely support getting webrtc: block into browsers at the very least before Chromium removes the 500 connection limit. Once that happens, I do not believe there is another way to disable WebRTC on android.

More than happy to help in any way with getting webrtc: block into browsers, solo-developing a browser feature was a bit intimidating but I'm more than happy to lend a hand if you all are going to make a serious effort at getting webrtc: block into Chromium.

Copy link
Member

@WofWca WofWca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again!

@@ -11,6 +11,7 @@
</head>
<body>
<div class="card" id="webrtc-output"></div>
<div class="iframe-allow-same-origin" style="display: none;"></div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be iframe-container instead of iframe-allow-same-origin? Also id instead of class. As in index.html.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this div entirely to align with the behavior of the other tests with iframes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants