Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
We want to use the stock Android WebView as a sandbox to execute local HTML/JS applications. A main security requirement is to set the WebView completely offline and only allow certain javascript interfaces to be called. These interfaces are passed into the javascript runtime using the WebView.addJavascriptInterface() method.
The Android application itself has the permission to access the network (android.permission.INTERNET).
I'm able to disable normal http/https requests,
but totally failed in blocking WebSocket requests
. It seems these are handled different to normal http requests.
One alternative is to overwrite the WebSocket JavaScript method. But this gives me a bad feeling as it is against the sandbox concept. It also seems to be possible to use
delete
to restore the original function pointer.
Another alternative would be to bundle an own customized WebView (e.g. Crosswalk-Project) with our application, but would like to avoid it as the compilation and updates are quite an effort.
I tried the following public WebView interfaces but none of them seems to block WebSocket calls:
webSettings.setBlockNetworkLoads(true);
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);
webView.setNetworkAvailable(false);
WebViewClient.shouldOverrideUrlLoading() (callback)
WebViewClient.shouldInterceptRequest() (callback, tried both versions)
WebChromeClient.onPermissionRequest()
Tested on Android 4.4.4 (19) and Android 5/5.1 (21/22).
The javascript I'm executing:
ws = new WebSocket("wss://echo.websocket.org");
ws.onmessage = function(event) {
console.log("received: " + event.data);
ws.onclose = function() {
console.log("External Socket closed");
ws.onopen = function() {
console.log("Connected to external ws");
ws.send("Hello from " + navigator.userAgent);
Any ideas how this could be done?
Thanks a lot
–
–
–
Another possible approach is to include a content security policy in the source of the page loaded into the webview:
<meta http-equiv="Content-Security-Policy" content="connect-src 'none';"/>
with this in place, I found that constructing the websocket instance for echo.websocket.org
simply throws an error and logs a CSP violation to the console.
Alternatively you could set this header in your ShouldInterceptRequest
method; here's a simplified example:
public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest request)
using (var stream = view.Context.Assets.Open("test.html"))
var resp = new WebResourceResponse("text/html", "UTF-8", stream);
resp.ResponseHeaders = new Dictionary<string, string>();
resp.ResponseHeaders.Add("Content-Security-Policy", "connect-src 'none';");
return resp;
Note that requests to file:///android_asset/...
and file:///android_res/...
addresses don't trigger the intercept method, but other file:///...
addresses do.
Also be aware that I've only tested this technique on Android 8.0. Apparently Chrome has supported CSP since 2013, but I can't say for sure what this means for Android's implementation.
On the topic of CSPs, it may be worth setting a more comprehensive policy for offline pages. Assuming the origin is file://
, perhaps something like this:
default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob: filesystem:;
Unfortunately, there is currently no way of intercepting WebSockets calls in WebView. You can only block out entire JavaScript execution or network access. You are correct that trying to override WebSocket
constructor with your own implementation can be worked around easily by deleting the overridden window property, so the built-in constructor accessible from the window
prototype chain gets visible again. The same will happen if you try to override WebSocket
with WebView.addJavascriptInterface
.
I think, HTML Application Cache is also not intercepted by WebView callbacks, and it doesn't even require Javascript to be turned on in order to work.
I guess, your only chance for creating a WebView network sandbox with the system WebView is to use a dedicated app with no network access, and communicate to it using Binder IPC.
Bundling customized WebView will create even more difficulties, as you will need to find out and plug all the holes, and then keep updating it with security fixes on your own.
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.