feat(android): Introduce setSupportMultipleWindows to mitigate CVE-2020-6506 (#1747 by @mrcoinbase and @kelset -- THANK YOU!)

BREAKING CHANGE:

This release introduces the `setSupportMultipleWindows` prop for Android. This sets the underlying Android WebView setting `setSupportMultipleWindows`. This prop defaults to `true` (previously `false`), and serves to mitigate the security advisory [CVE-2020-6506](https://github.com/react-native-webview/react-native-webview/security/advisories/GHSA-36j3-xxf7-4pqg).

The primary way this new behavior changes existing React Native WebView implementations on Android is that links that open in new tabs/windows (such as `<a target="_blank">`) will now prompt to open in the system browser, rather than re-using the current WebView.

If this behavior is not desirable, you can set this new prop to `false`, but be aware that this exposes your app to the security vulnerability listed above. Make sure you have read and understand the whole advisory and relevant links.

iOS & Windows are unaffected.

```jsx
<WebView
  // ...
  setSupportMultipleWindows={true} // default: true
/>
```

Thanks to @mrcoinbase, @kelset, and @Titozzz for their work on this.
This commit is contained in:
Lorenzo Sciandra
2020-11-24 09:15:19 -08:00
committed by GitHub
parent 1b009dd746
commit 194c6a2335
6 changed files with 83 additions and 3 deletions
@@ -13,6 +13,7 @@ import android.net.http.SslError;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Message;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
@@ -187,6 +188,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(false);
settings.setDomStorageEnabled(true);
settings.setSupportMultipleWindows(true);
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);
@@ -252,6 +254,11 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
view.getSettings().setJavaScriptEnabled(enabled);
}
@ReactProp(name = "setSupportMultipleWindows")
public void setSupportMultipleWindows(WebView view, boolean enabled){
view.getSettings().setSupportMultipleWindows(enabled);
}
@ReactProp(name = "showsHorizontalScrollIndicator")
public void setShowsHorizontalScrollIndicator(WebView view, boolean enabled) {
view.setHorizontalScrollBarEnabled(enabled);
@@ -875,7 +882,7 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
// This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request.
String topWindowUrl = webView.getUrl();
String failingUrl = error.getUrl();
// Cancel request after obtaining top-level URL.
// If request is cancelled before obtaining top-level URL, undesired behavior may occur.
// Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL.
@@ -1073,6 +1080,17 @@ public class RNCWebViewManager extends SimpleViewManager<WebView> {
this.mWebView = webView;
}
@Override
public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg) {
final WebView newWebView = new WebView(view.getContext());
final WebView.WebViewTransport transport = (WebView.WebViewTransport) resultMsg.obj;
transport.setWebView(newWebView);
resultMsg.sendToTarget();
return true;
}
@Override
public boolean onConsoleMessage(ConsoleMessage message) {
if (ReactBuildConfig.DEBUG) {