JS与WebView交互存在的一些问题

一、背景概述

2013年Android平台暴露出WebView漏洞。利用该漏洞,攻击者可以通过存在风险的addJavascriptInterface接口函数提供的扩展穿透webkit执行本地Java代码,造成恶意代码在受害人的手机上执行,并可能进一步执行木马。
目前,google公司仅对Android4.2及以上系统提供了规避方法,Android4.2以下所有版本尚无官方解决方案。
本文将就上述漏洞提出相应的解决方案。

Android API level 16以及之前的版本存在远程代码执行安全漏洞,该漏洞源于程序没有正确限制使用WebView.addJavascriptInterface方法,远程攻击者可通过使用Java Reflection API利用该漏洞执行任意Java对象的方法,简单的说就是通过addJavascriptInterface给WebView加入一个JavaScript桥接接口,JavaScript通过调用这个接口可以直接操作本地的JAVA接口。
该漏洞公布的近期,多款Android流行应用曾被曝出高危挂马漏洞:点击消息或朋友社区圈中的一条网址时,用户手机然后就会自动执行被挂马的代码指令,从而导致被安装恶意扣费软件、向好友发送欺诈短信、通讯录和短信被窃取以及被远程控制等严重后果。在乌云漏洞平台上,包括Android版的微信、QQ、腾讯微博、QQ浏览器、快播、百度浏览器、金山浏览器等大批TOP应用均被曝光同类型的漏洞。

不可避免,由于公司中,修旧并行的架构中,涉及很多的WebView和JS交互的功能实现点。安全部已经发布方案,需要我们修改。最近一直在做这方面的研究。
引用:【http://blog.csdn.net/leehong2005/article/details/11808557#
使用WebView来展示一个网页,现在很多应用为了做到服务端可控,很多结果页都是网页的,而不是本地实现,这样做有很多好处,比如界面的改变不需要重新发布新版本,直接在Server端修改就行了。用网页来展示界面,通常情况下都或多或少都与Java代码有交互,比如点击网页上面的一个按钮,我们需要知道这个按钮点击事件,或者我们要调用某个方法,让页面执行某种动作,为了实现这些交互,我们通常都是使用JS来实现,而WebView已经提供了这样的方法,具体用法如下:
< mWebView.getSettings().setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");>

我们向WebView注册一个名叫“jsInterface”的对象,然后在JS中可以访问到jsInterface这个对象,就可以调用这个对象的一些方法,最终可以调用到Java代码中,从而实现了JS与Java代码的交互。
我们一起来看看关于addJavascriptInterface方法在Android官网的描述:

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.
JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
The Java object's fields are not accessible.

简单地说,就是用addJavascriptInterface可能导致不安全,因为JS可能包含恶意代码。今天我们要说的这个漏洞就是这个,当JS包含恶意代码时,它可以干任何事情。

二、实现方案

1、Android 4.2以上的系统

Android 4.2以上系统,通过在Java的远程方法上面声明@JavascriptInterface可以解决WebView漏洞。如下面代码:

    class JsObject {  
           @JavascriptInterface  
           public String toString() { return "injectedObject"; }  
        }  

2、Android 4.2以下的系统

若客户端需要兼容支持Android 4.2以下的系统版本,建议使用本方案规避WebView漏洞。本方案分为两个修改要点,建议对于https和http场景均使用下述方法规避风险。

修改点一:使用安全方法替代addJavascriptInterface

对于Android 4.2以下的系统Google公司官方没有提供解决方案。为替代addJavascriptInterface方法,可以利用prompt方法传参以完成java与js的交互。对应java中的onJsPrompt方法的声明如下:
public boolean onJsPrompt( WebView view, String url, String message, String defaultValue, JsPromptResult result )
通过这个方法,JS能把信息(文本)传递到Java,而Java也能把信息(文本)传递到JS中。

具体实施方法如下:

1)让JS调用一个Javascript方法,在这个方法中调用prompt方法,通过prompt把JS中的信息传递过来,这些信息应该是我们组合成的一段有意义的文本,可能包含:特定标识,参数等。在onJsPrompt方法中,我们去解析传递过来的文本,得到约定好的特定标识,参数等,再通过特定标识调用指定的java方法,并传入参数。具体的Java代码如下:

final class MyWebChromeClient extends WebChromeClient 
{   
    public boolean onJsPrompt( WebView view, String url, String message, String defaultValue, JsPromptResult result )
    {
        if( message.equals("1") )
          {
          //解析参数defaultValue
        //调用java方法并得到结果
           }
           //返回结果
        result.confirm("result");
        return true;
    }
}

2)关于返回值,可以通过result返回回去,这样就可以把Java中方法的处理结果返回到Js中。
3)在Javascript方法中,通过调用prompt方法传入标识和参数(依次对应onJsPrompt方法中的message、defaultValue参数),以通知java需要使用的方法及对应参数。prompt方法中第一个参数可以传送约定好的特定方法标识,prompt方法中第二个参数可以传入对应的参数序列。具体的Javascript代码如下:

   function showHtmlcallJava()
   {
      var ret = prompt( "1", "param1;param2" );
     //ret值即为java传回的”result”
     //根据返回内容作相应处理
    }

修改点二:移除系统开放的JS接口

对于Android 3.0以上版本,Android系统开放了部分JS接口。因此在这个版本范围下,尽管客户端自身没有使用addJavascriptInterface方法,黑客仍可以透过系统开放的JS接口实施恶意操作。
针对上述风险,客户端可通过下面的方法移除风险接口。具体实施方法如下:
1)使用removeJavascriptInterface方法移除操作系统开放的"searchBoxJavaBridge_"、"accessibility"、"accessibilityTraversal"接口。由于removeJavascriptInterface方法只在Android API 11以上版本支持,因此若客户端需要支持Android API 11以下版本,需要在使用该方法时声明目标API。
@TargetApi(Build.VERSION_CODES.HONEYCOMB) private void dealJavascriptLeak() { mWebView.removeJavascriptInterface("searchBoxJavaBridge_"); mWebView.removeJavascriptInterface("accessibility"); mWebView.removeJavascriptInterface("accessibilityTraversal"); }
2)针对Android3.0以上系统版本移除问题接口。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { dealJavascriptLeak(); }

三、总结

对于https和http协议访问的页面,开发过程中须注意弃用存在漏洞的addJavascriptInterface方法,通过使用prompt方法传参,完成java与js的交互。同时客户端须移除系统开放的JS接口,全面规避WebView漏洞风险。

详细修步骤:

【1】让JS调用一个Javascript方法,这个方法中是调用prompt方法,通过prompt把JS中的信息传递过来,这些信息应该是我们组合成的一段有意义的文本,可能包含:特定标识,方法名称,参数等。在onJsPrompt方法中,我们去解析传递过来的文本,得到方法名,参数等,再通过反射机制,调用指定的方法,从而调用到Java对象的方法。
【2】关于返回值,可以通过prompt返回回去,这样就可以把Java中方法的处理结果返回到Js中。
【3】我们需要动态生成一段声明Javascript方法的JS脚本,通过loadUrl来加载它,从而注册到html页面中,具体的代码如下:

javascript:(function JsAddJavascriptInterface_(){
if (typeof(window.jsInterface)!='undefined') {    
    console.log('window.jsInterface_js_interface_name is exist!!');} 
else {
    window.jsInterface = {        
        onButtonClick:function(arg0) { 
            return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]}));
        },
        onImageClick:function(arg0,arg1,arg2) {   prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}));
        },
    };
     }
   }
        )()

说明:
1,上面代码中的jsInterface就是要注册的对象名,它注册了两个方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2),如果有返回值,就添加上return。
2,prompt中是我们约定的字符串,它包含特定的标识符MyApp:,后面包含了一串JSON字符串,它包含了方法名,参数,对象名等。
3,当JS调用onButtonClick或onImageClick时,就会回调到Java层中的onJsPrompt方法,我们再解析出方法名,参数,对象名,再反射调用方法。
4,window.jsInterface这表示在window上声明了一个Js对象,声明方法的形式是:方法名:function(参数1,参数2)
5,一些思考
以下是在实现这个解决方案过程中遇到的一些问题和思考:
【1】生成Js方法后,加载这段Js的时机是什么?
刚开始时在当WebView正常加载URL后去加载Js,但发现会存在问题,如果当WebView跳转到下一个页面时,之前加载的Js就可能无效了,所以需要再次加载。这个问题经过尝试,需要在以下几个方法中加载Js,它们是WebChromeClient和WebViewClient的方法:
· onLoadResource
· doUpdateVisitedHistory
· onPageStarted
· onPageFinished
· onReceivedTitle
· onProgressChanged
目前测试了这几个地方,没什么问题,这里我也不能完全确保没有问题。

【2】需要过滤掉Object类的方法
由于通过反射的形式来得到指定对象的方法,他会把基类的方法也会得到,最顶层的基类就是Object,所以我们为了不把getClass方法注入到Js中,所以我们需要把Object的公有方法过滤掉。这里严格说来,应该有一个需要过滤方法的列表。目前我的实现中,需要过滤的方法有:
"getClass",
"hashCode",
"notify",
"notifyAll",
"equals",
"toString",
"wait",

【3】通过手动loadUrl来加载一段js,这种方式难道js中的对象就不在window中吗?也就是说,通过遍历window的对象,不能找到我们通过loadUrl注入的js对象吗?
关于这个问题,我们的方法是通过Js声明的,通过loadUrl的形式来注入到页面中,其实本质相当于把我们这动态生成的这一段Js直接写在Html页面中,所以,这些Js中的window中虽然包含了我们声明的对象,但是他们并不是Java对象,他们是通过Js语法声明的,所以不存在getClass之类的方法。本质上他们是Js对象。

【4】在Android 3.0以下,系统自己添加了一个叫searchBoxJavaBridge_的Js接口,要解决这个安全问题,我们也需要把这个接口删除,调用removeJavascriptInterface方法。这个searchBoxJavaBridge_好像是跟google的搜索框相关的。

【5】在实现过程中,我们需要判断系统版本是否在4.2以下,因为在4.2以上,Android修复了这个安全问题。我们只是需要针对4.2以下的系统作修复。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容