I have an application which acts like browser and display results in android webview. Among them, some results are rendered from my own server and uses javascriptInterface object to call Java methods.
Inside WebviewClient shouldOverrideUrlLoading() method, I added javascriptInterface only for selective urls of my server and removed javascriptInterface for remaining urls as code shown below:if(url.contains("mypage1.html")||url.contains("mypage2.html")){
webView.addJavascriptInterface(new JavaScriptInterface(),"XYZ");
}
else {
webView.removeJavascriptInterface("XYZ");
}
A dummy url myevilpage.html containing evil javascript is also loaded along with mypage1.html and mypage2.html. I have verified that myevilpage.html javascript couldn't call Java methods.
Is this approach okay for ensuring no urls other than my specific urls could bind using javascriptInterface bridge?
I have already referred the following links:
http://www.rapid7.com/db/modules/exploit/android/browser/webview_addjavascriptinterface
Android App using Webview/javascript. what can be security concern?
Android JavascriptInterface Security?
Asked
Active
Viewed 1,674 times
2

Community
- 1
- 1

r.bhardwaj
- 1,603
- 6
- 28
- 54
1 Answers
1
Is this approach okay for ensuring no urls other than my specific urls could bind using javascriptInterface bridge?
No. You are using contains()
and not equals()
, so an attacker can trivially craft a URL that happens to have those substrings. Also, there may be timing issues, as you are determining the availability of the JS interface before that page is loaded, which means you are immediately affecting the currently-loaded page.
There would still be other possible attacks (e.g., proxy servers, evil JS served by those pages through ad networks or other third-party sources) that URL detection would not catch, though addressing those would be difficult at best.

CommonsWare
- 986,068
- 189
- 2,389
- 2,491
-
Yes you are right that there should be equals(). For the timing issues you mentioned, I have verified with my dummy evil url and the evil javascript in it couldn't call Java methods. Also as per android documentation, the **url** parameter in shouldOverrideUrlLoading method is the new url **about to be loaded** in the current WebView. – r.bhardwaj May 08 '14 at 06:17
-
Also, I am adding javascriptInterface for only **specific urls** rendered over SSL link so unless and until **other possible attacks** occur on my specific urls , how can those attacks affect my application? – r.bhardwaj May 08 '14 at 06:26
-
@r.bhardwaj: "Also as per android documentation, the url parameter in shouldOverrideUrlLoading method is the new url about to be loaded in the current WebView" -- correct. That means that you are changing the characteristics of the `WebView` for the page that is *currently* loaded, before the `WebView` loads the page indicated by the supplied URL. `WebView` has its own threading model, and I have no idea if they have suspended web workers, etc. while all of this is going on. – CommonsWare May 08 '14 at 11:06
-
2`shouldOverrideUrlLoading` will not allow the page to start loading before you return from the method, however `add/removeJavaScriptInterface` are _asynchronous_ so it's technically possible for those to arrive _after_ the malicious JavaScript had had a chance to run. IMHO a better solution would be to use two WebViews (a trusted and untrusted one) and switch between them. – marcin.kosiba May 09 '14 at 15:30
-
@marcin.kosiba: I got your point but I have to use single webview for my application as it behaves like browser which contains history stack for navigation(backward/forward). My final implementation is like this: "I am adding JavaScriptInterface before loading my specific urls(mypage1.html, mypage2.html) using loadUrl(). Now suppose "mypage1.html" displays multiple links and one of those is a malicious link "myevilpage.html"( which contains evil javascript or iframe with evil script etc). When user clicks on this link, shouldOverrideUrlLoading method is called and I am removing bridge there. – r.bhardwaj May 13 '14 at 09:52
-
@marcin.kosiba: "add/removeJavaScriptInterface are asynchronous so it's technically possible for those to arrive after the malicious JavaScript had chance to run" -- I have tested with dummy evil urls with evil Javascript and some also use iframe for evil javascript but found that JavaScriptInterface bridge got removed before page could call it's evil javascript. Can you please elaborate how can I achieve what you have stated and also is there any way to know when exactly add/removeJavaScriptInterface calls are executed ? – r.bhardwaj May 13 '14 at 10:02
-
@r.bhardwaj - there are no callbacks on those APIs so there is no way for you to know when they have taken effect. – marcin.kosiba May 13 '14 at 14:26
-
@r.bhardwaj There are no tests in the WebView codebase to make sure `add/removeJavaScriptInterface` takes effect if it's called from shouldOverrideUrlLoading. Just because you don't hit it on your device on your particular version doesn't mean it can't happen or it won't start happening in a future WebView release. The `addJavaScriptInterface` API should not be used on a WebView that deals with untrusted content. – marcin.kosiba May 13 '14 at 14:44
-
@marcin.kosiba,@CommonsWare: My main motive of calling Java methods from Javascript is to retrieve some values needed in the app during runtime(I can't store them in the device for some privacy issues). I have come across some approaches like: webView.loadUrl("javascript:console.log(functionThatReturnsSomething)"); webView.loadUrl("javascript:alert(functionThatReturnsSomething)"); And then using onJsAlert() or onConsoleMessage() webchromeclient methods to retrieve them. Are these approaches okay to handle security issues ? – r.bhardwaj May 16 '14 at 14:39
-
1@r.bhardwaj - that's certainly better as you wouldn't run the risk of arbitrary code execution. The only remaining issue is the 'usual' problem that any page (and subframe) can call either alert or console.log. The code to handle onConsoleMessage/onJsAlert should be written with that in mind. Also, something like loadUrl("javascript:console.log('"+randomNumber+":' + function())"); and only trusting callbacks that contain the right number would make it harder for any potential attacker to trick your app. – marcin.kosiba May 16 '14 at 14:54
-
@r.bhardwaj you said "values needed in the app during runtime (I can't store them in the device for some privacy issues)" which seems unusual. Normally it's sending data from the device to the server that causes privacy concerns. – marcin.kosiba May 16 '14 at 14:56
-
@marcin.kosiba: By privacy issues here in my app, I avoid using storage options internal, external, SQlite or SharedPreferences for storing info like settings, search term etc. Also I am avoiding webview cookies and other info. Basically, I am having static variables which store values(like post parameters etc) passed from server to Android method(through JavascriptInterface bridge). So, now I am planning to retrieve these values using onConsoleMessgae() or onJsAlert() keeping in mind the that only my specific urls can take benefit of these methods. – r.bhardwaj May 19 '14 at 06:53
-
@marcin.kosiba: Can you tell me that if I call multiple console.log('"+randomNumber+":' + function()); with different "function()", then will I receive multiple onConsoleMessage() ? – r.bhardwaj May 19 '14 at 07:06
-
@r.bhardwaj - yes, you will receive multiple `onConsoleMessage` callbacks. I still don't understand _why_ you're avoiding storing data on the device though. – marcin.kosiba May 19 '14 at 08:59
-
@marcin.kosiba: This is as per app requirements. If anyone accesses the device, then he/she should not find out what user have searched, also any third party page couldn't access user related info like cookies and all. – r.bhardwaj May 19 '14 at 10:55
-
@r.bhardwaj - the WebView, like any other browser, should ensure third party pages can't steal your cookies (based on origin checks). Those are some interesting app requirements - do you require the user to log in every time the app starts? – marcin.kosiba May 19 '14 at 16:43
-
@marcin.kosiba: Actually, the app behaves like a browser(which doesn't store any user info) and where results are displayed from our secure server(search engine). There is no native login functionality in the app. – r.bhardwaj May 21 '14 at 05:18
-
@marcin.kosiba: Is there anyway to use "hostname" as identifier(randomNumber you mentioned) to make it impossible for attacker to trick the app? – r.bhardwaj May 21 '14 at 10:13
-
@r.bhardwaj - nothing makes it impossible. if used correctly a random number is hard for the attacker to guess, the hostname is probably easier. – marcin.kosiba May 21 '14 at 10:54
-
@marcin.kosiba: If I entertain the code inside onConsoleMessage/onJsAlert only when the webview.getUrl() is my specific url, then I suppose the problem can be overcomed. Right ? – r.bhardwaj May 21 '14 at 11:17