我们很多时候要使用WebView来展示一个网页,现在很多应用为了做到服务端可控,很多结果页都是网页的,而不是本地实现,这样做有很多好处,比如界面的改变不需要重新发布新版本,直接在Server端修改就行了。用网页来展示界面,通常情况下都或多或少都与Java代码有交互,比如点击网页上面的一个按钮,我们需要知道这个按钮点击事件,或者我们要调用某个方法,让页面执行某种动作,为了实现这些交互,我们通常都是使用JS来实现,而WebView已经提供了这样的方法,具体用法如下:
- mWebView.getSettings().setJavaScriptEnabled(true);
- mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
我们向WebView注册一个名叫“jsInterface”的对象,然后在JS中可以访问到jsInterface这个对象,就可以调用这个对象的一些方法,最终可以调用到Java代码中,从而实现了JS与Java代码的交互。
但是用addJavascriptInterface可能导致不安全,因为JS可能包含恶意代码。
假如我们自己没有添加addJavascriptInterface,甚至默认为false呢。?还是有漏洞!因为在低于API17的WebView上默认添加"searchBoxJavaBridge_"到mJavaScriptObjects中。
这样就有可能通过用户信任的客户端获取SD卡的数据。
解决方法有几点:
1. 过滤本地文件的访问:
- if (!url.startsWith("file://")) {
-
- }
2. 过滤未知网站(可以非本站点的都不允许加载)
3. 删除默认添加的"searchBoxJavaBridge_"
-
- if (Build.VERSION.SDK_INT > 10&&Build.VERSION.SDK_INT < 17) {
- fixWebView();
- }
-
-
- @TargetApi(11)
- private void fixWebView() {
-
-
-
-
- mWebView.removeJavascriptInterface("searchBoxJavaBridge_");
- }
4.
(prompt()$onJsPrompt()/confirm()$onConfirm()/alert()$onAlert()):
继承该WebChromeClient重写以上三个
方法其中一个的具体实现
class HarlanWebChromeClient extends WebChromeClient {
/*此处覆盖的是javascript中的alert方法。
*当网页需要弹出alert窗口时,会执行onJsAlert中的方法
* 网页自身的alert方法不会被调用。
*/
@Override
public boolean onJsAlert(WebView view, String url, String message,
JsResult result) {
show("onJsAlert");
result.confirm();
return true;
}
/*此处覆盖的是javascript中的confirm方法。
*当网页需要弹出confirm窗口时,会执行onJsConfirm中的方法
* 网页自身的confirm方法不会被调用。
*/
@Override
public boolean onJsConfirm(WebView view, String url,
String message, JsResult result) {
show("onJsConfirm");
result.confirm();
return true;
}
/*此处覆盖的是javascript中的confirm方法。
*当网页需要弹出confirm窗口时,会执行onJsConfirm中的方法
* 网页自身的confirm方法不会被调用。
*/
@Override
public boolean onJsPrompt(WebView view, String url,
String message, String defaultValue,
JsPromptResult result) {
show("onJsPrompt....");
result.confirm();
return true;
}
然后给webView设置该重写的类
//设置ChromeClient
mWebView.setWebChromeClient(new HarlanWebChromeClient());
相应的在JS中的具体实现代码如下
function cfm() {
confirm("")
}
function pmt() {
prompt("","");
}
function onAlert()
{
alert("这是网页中的alert方法,如果重写了mWebView的onAlert方法,该方法不会执行");
}
触发页面中的js函数,例如:
<p><input type="button" onclick="cfm()" value="Confirm"/></p>
<p><input type="button" onclick="pmt()" value="Prompt"/></p>
<p><input type="button" onclick="onAlert()" value="Alert"/>
实现原理就是在页面中触发的方法被webView中设置的WebChromeClient给拦截了,从而执行了WebChromeClient中重写的onXxx()方法, 没有执行页面中相应的onXxx()方法,这是方式相对简单,而且安全。
参考链接: https://github.com/Sunzxyong/RainbowBridge
http://blog.youkuaiyun.com/owillll/article/details/20996139