2013年6月14日金曜日

[Android][Java][JavaScript] Android4.2以上でaddJavascriptInterfaceに制限がついた

AndroidではJavaとJavaScriptの連携が非常に簡単にできる。

public class AndroidAPI
{
    private final static String TAG="API";

    public void call()
    {
        Log.d(TAG,"JavaScript call");
    }
}

とJavaScriptに公開するクラスを用意しておき

WebView webView=new WebView(context);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new AndroidAPI(),"API");

とするだけでWebViewのJavaScriptからAndroidAPIというクラスのメソッドにアクセスできるようになる。
実際にJavaScript側でどう使うかと言えば

<script>
API.call();
</script>

とaddJavascriptInterfaceの第二引数で指定した名前のオブジェクトができているので、
後はJavaScriptのオブジェクトとしてアクセスできる。
そのためそのオブジェクトのメソッドを呼ぶことができる。

さて、ここで今回の本題だが
Nexus 7やGalaxy S4などのAndroid4.2以上を搭載している端末では、
オブジェクトはできているがメソッドが定義されていないというエラーがJavaScript側で出てしまう。

そこでWebView | Android DevelopersのaddJavascriptInterfaceを見てみると、
4.2以上からは@JavascriptInterfaceがついているpublicメソッドのみアクセスできるとなっている。
なので先ほど定義したJavaScriptに公開するクラスのメソッドに

public class AndroidAPI
{
    private final static String TAG="API";

    @JavascriptInterface
    public void call()
    {
        Log.d(TAG,"JavaScript call");
    }
}

という風にアノテーションをきちんとつけてあげると、
無事にJavaScriptからメソッドが呼び出せるようになる。
ちなみに@JavascriptInterfaceはandroid.webkit.JavascriptInterfaceをimportすれば使えるようになる。

ちなみに4.2未満の場合は(継承されているクラスも含め)publicなメソッドであれば
すべてアクセスできていた。
特にこれでも問題ないように思うかもしれないがJavaにはリフレクションがあるため、
その気になればprivateなメンバやメソッドにもアクセスできてしまう。
privateメソッドなんかの名前はapkファイルをデコンパイルすれば難読化されてない限り簡単に調べることができる。
故に公開したクラスの中にcontextを持っているとJavaScriptからcontextを取得できてしまい、アプリケーションの権限によっては電話帳などの情報にもアクセスできてしまう。
そんな状態のアプリケーションが公開されXSS(クロスサイトスクリプティング)攻撃の恐れがあるサイトにWebViewでアクセスされると個人情報が抜き取られる恐れがある。

故にこのような仕様変更が起こったのであろう。
もし可能なら4.2未満の端末ではaddJavascriptInterfaceを使わないのが望ましい。

0 件のコメント:

コメントを投稿