Aug
31
大家都知道,在android的webview中,有非常非常严重的bug。
那就是4.2以下的webview的JavascriptInterface可以访问任何java本地代码,以至于程序完全被劫持。
更惨的是,android旧版本自带一个searchBoxJavaBridge_的接口,导致漏洞直接暴露在互联网中。
查看乌云上近年来的记录,大到微信,小到快车,无数app都经历过次劫。
android4.2以上修复了这个bug,并提供了更安全的解决方案:在提供的方法前添加注解:@ JavascriptInterface
因此,我们需要一个合理的解决方案。
当然,方法很多,比较推荐的是微信采用的jsbridge方案(参看解包微信的源码,js代码并没有混淆)。
然而对于安卓开发者,我想追求一种更优雅的,可以和4.2以上官方方案自然衔接的方案。
于是我编写库:ExtendJavascriptInterface(https://github.com/Lrdcq/ExtendJavascriptInterface/)
首先请看它的使用方法:
首先我们以4.2以上版本的方法定义js接口:
挺好的,所以我希望旧版用相同的东西就可以了,因此旧版也用相同的方法定义接口。
其次,怎么使用呢,简单来说看起来会是这样:
主要的区别集中在webview怎样添加JavascriptInterface和setWebChromeClient上,如果是4.2以上,一切安好;如果是旧版本,就用这段代码提供的方法咯。
另外记得remove掉searchBoxJavaBridge_,仅此而已。
看起来很简单吧。
那么这个方法的内部原理是怎样的呢?
1.首先,我们用反射注解把拥有@JavascriptInterface注解的方法数据化,并且把这些方法用数据化的方式暂存起来。
2.然后,webview也加载好了,我们用bridge的方法的数据构成一段js,用loadurl把js直接注入网页中。
3.这段js做的事情是,在js中注入与bridge方法名相同的全局函数或者方法,然后就可以表示bridge加载完成,js可以使用这些方法了
4.当在js使用这些方法的时候,我们重写了在移动开发中几乎用不到的alert函数,js出发alert,按一定格式把数据json化发出去。
5.android重写onJsAlert然后截取到发过来的数据,可以看到是名字叫什么的函数,参数是些什么。
6.最后,找到之前解释注解储存的方法,对应的找出来,invoke出来~即可~
7.同时,我们也考虑提供回调方法,当通信完成后产生回调事件并触发。
这样,绕过自带的JsBridge并实现看起来像自带的JsBridge的功能就完成了。
那就是4.2以下的webview的JavascriptInterface可以访问任何java本地代码,以至于程序完全被劫持。
更惨的是,android旧版本自带一个searchBoxJavaBridge_的接口,导致漏洞直接暴露在互联网中。
查看乌云上近年来的记录,大到微信,小到快车,无数app都经历过次劫。
android4.2以上修复了这个bug,并提供了更安全的解决方案:在提供的方法前添加注解:@ JavascriptInterface
因此,我们需要一个合理的解决方案。
当然,方法很多,比较推荐的是微信采用的jsbridge方案(参看解包微信的源码,js代码并没有混淆)。
然而对于安卓开发者,我想追求一种更优雅的,可以和4.2以上官方方案自然衔接的方案。
于是我编写库:ExtendJavascriptInterface(https://github.com/Lrdcq/ExtendJavascriptInterface/)
首先请看它的使用方法:
首先我们以4.2以上版本的方法定义js接口:
public class JsBridge {
@JavascriptInterface
public String send(String str) {
wvBox.loadUrl("javascript:do2('-"+str+"-')");
return "javagot:" + str;
}
@JavascriptInterface
public void toast(String message) {
Toast.makeText(wvBox.getContext(), message, Toast.LENGTH_SHORT).show();
}
}
挺好的,所以我希望旧版用相同的东西就可以了,因此旧版也用相同的方法定义接口。
其次,怎么使用呢,简单来说看起来会是这样:
JsBridge bridge = new JsBridge();
wvBox = (WebView) findViewById(R.id.webview);
wvBox.removeJavascriptInterface("searchBoxJavaBridge_");
wvBox.loadUrl(fromUrl());
//
wvBox.getSettings().setJavaScriptEnabled(true);
//!!!!!!!!!!!!!!!!!!!!!!使用方法!!!!!!!!!!!!!!!!!
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.JELLY_BEAN_MR1) {//4.2以下危险webview的使用本方法
ExtendJavascriptInterface<JsBridge> t=new ExtendJavascriptInterface(bridge,bridgeName);
wvBox.setWebChromeClient(new ExtendJavascriptInterfaceClient(t));
}else{//正常用法
wvBox.addJavascriptInterface(bridge,bridgeName);
wvBox.setWebChromeClient(new WebChromeClient());
}
//!!!!!!!!!!!!!!!!!!!!!使用方法结束!!!!!!!!!!!!!!
主要的区别集中在webview怎样添加JavascriptInterface和setWebChromeClient上,如果是4.2以上,一切安好;如果是旧版本,就用这段代码提供的方法咯。
另外记得remove掉searchBoxJavaBridge_,仅此而已。
看起来很简单吧。
那么这个方法的内部原理是怎样的呢?
1.首先,我们用反射注解把拥有@JavascriptInterface注解的方法数据化,并且把这些方法用数据化的方式暂存起来。
2.然后,webview也加载好了,我们用bridge的方法的数据构成一段js,用loadurl把js直接注入网页中。
3.这段js做的事情是,在js中注入与bridge方法名相同的全局函数或者方法,然后就可以表示bridge加载完成,js可以使用这些方法了
4.当在js使用这些方法的时候,我们重写了在移动开发中几乎用不到的alert函数,js出发alert,按一定格式把数据json化发出去。
5.android重写onJsAlert然后截取到发过来的数据,可以看到是名字叫什么的函数,参数是些什么。
6.最后,找到之前解释注解储存的方法,对应的找出来,invoke出来~即可~
7.同时,我们也考虑提供回调方法,当通信完成后产生回调事件并触发。
这样,绕过自带的JsBridge并实现看起来像自带的JsBridge的功能就完成了。