一臭杰、背景概述
2013年Android平臺暴露出WebView漏洞猜丹。利用該漏洞,攻擊者可以通過存在風險的addJavascriptInterface接口函數(shù)提供的擴展穿透webkit執(zhí)行本地Java代碼硅卢,造成惡意代碼在受害人的手機上執(zhí)行射窒,并可能進一步執(zhí)行木馬。
目前将塑,google公司僅對Android4.2及以上系統(tǒng)提供了規(guī)避方法脉顿,Android4.2以下所有版本尚無官方解決方案。
本文將就上述漏洞提出相應(yīng)的解決方案点寥。
Android API level 16以及之前的版本存在遠程代碼執(zhí)行安全漏洞艾疟,該漏洞源于程序沒有正確限制使用WebView.addJavascriptInterface方法,遠程攻擊者可通過使用Java Reflection API利用該漏洞執(zhí)行任意Java對象的方法敢辩,簡單的說就是通過addJavascriptInterface給WebView加入一個JavaScript橋接接口蔽莱,JavaScript通過調(diào)用這個接口可以直接操作本地的JAVA接口。
該漏洞公布的近期戚长,多款A(yù)ndroid流行應(yīng)用曾被曝出高危掛馬漏洞:點擊消息或朋友社區(qū)圈中的一條網(wǎng)址時盗冷,用戶手機然后就會自動執(zhí)行被掛馬的代碼指令,從而導(dǎo)致被安裝惡意扣費軟件同廉、向好友發(fā)送欺詐短信仪糖、通訊錄和短信被竊取以及被遠程控制等嚴重后果。在烏云漏洞平臺上迫肖,包括Android版的微信锅劝、QQ、騰訊微博蟆湖、QQ瀏覽器故爵、快播、百度瀏覽器隅津、金山瀏覽器等大批TOP應(yīng)用均被曝光同類型的漏洞诬垂。
不可避免,由于公司中饥瓷,修舊并行的架構(gòu)中剥纷,涉及很多的WebView和JS交互的功能實現(xiàn)點。安全部已經(jīng)發(fā)布方案呢铆,需要我們修改晦鞋。最近一直在做這方面的研究。
引用:【http://blog.csdn.net/leehong2005/article/details/11808557#】
使用WebView來展示一個網(wǎng)頁,現(xiàn)在很多應(yīng)用為了做到服務(wù)端可控悠垛,很多結(jié)果頁都是網(wǎng)頁的线定,而不是本地實現(xiàn),這樣做有很多好處确买,比如界面的改變不需要重新發(fā)布新版本斤讥,直接在Server端修改就行了。用網(wǎng)頁來展示界面湾趾,通常情況下都或多或少都與Java代碼有交互芭商,比如點擊網(wǎng)頁上面的一個按鈕,我們需要知道這個按鈕點擊事件搀缠,或者我們要調(diào)用某個方法铛楣,讓頁面執(zhí)行某種動作,為了實現(xiàn)這些交互艺普,我們通常都是使用JS來實現(xiàn)簸州,而WebView已經(jīng)提供了這樣的方法,具體用法如下:
< mWebView.getSettings().setJavaScriptEnabled(true); mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");>
我們向WebView注冊一個名叫“jsInterface”的對象歧譬,然后在JS中可以訪問到j(luò)sInterface這個對象岸浑,就可以調(diào)用這個對象的一些方法,最終可以調(diào)用到Java代碼中瑰步,從而實現(xiàn)了JS與Java代碼的交互矢洲。
我們一起來看看關(guān)于addJavascriptInterface方法在Android官網(wǎng)的描述:
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可能導(dǎo)致不安全面氓,因為JS可能包含惡意代碼兵钮。今天我們要說的這個漏洞就是這個,當JS包含惡意代碼時舌界,它可以干任何事情。
二泰演、實現(xiàn)方案
1呻拌、Android 4.2以上的系統(tǒng)
Android 4.2以上系統(tǒng),通過在Java的遠程方法上面聲明@JavascriptInterface可以解決WebView漏洞睦焕。如下面代碼:
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
2藐握、Android 4.2以下的系統(tǒng)
若客戶端需要兼容支持Android 4.2以下的系統(tǒng)版本,建議使用本方案規(guī)避WebView漏洞垃喊。本方案分為兩個修改要點猾普,建議對于https和http場景均使用下述方法規(guī)避風險。
修改點一:使用安全方法替代addJavascriptInterface
對于Android 4.2以下的系統(tǒng)Google公司官方?jīng)]有提供解決方案本谜。為替代addJavascriptInterface方法初家,可以利用prompt方法傳參以完成java與js的交互。對應(yīng)java中的onJsPrompt方法的聲明如下:
public boolean onJsPrompt( WebView view, String url, String message, String defaultValue, JsPromptResult result )
通過這個方法,JS能把信息(文本)傳遞到Java溜在,而Java也能把信息(文本)傳遞到JS中陌知。
具體實施方法如下:
1)讓JS調(diào)用一個Javascript方法,在這個方法中調(diào)用prompt方法掖肋,通過prompt把JS中的信息傳遞過來仆葡,這些信息應(yīng)該是我們組合成的一段有意義的文本,可能包含:特定標識志笼,參數(shù)等沿盅。在onJsPrompt方法中,我們?nèi)ソ馕鰝鬟f過來的文本纫溃,得到約定好的特定標識腰涧,參數(shù)等,再通過特定標識調(diào)用指定的java方法皇耗,并傳入?yún)?shù)南窗。具體的Java代碼如下:
final class MyWebChromeClient extends WebChromeClient
{
public boolean onJsPrompt( WebView view, String url, String message, String defaultValue, JsPromptResult result )
{
if( message.equals("1") )
{
//解析參數(shù)defaultValue
//調(diào)用java方法并得到結(jié)果
}
//返回結(jié)果
result.confirm("result");
return true;
}
}
2)關(guān)于返回值,可以通過result返回回去郎楼,這樣就可以把Java中方法的處理結(jié)果返回到Js中万伤。
3)在Javascript方法中,通過調(diào)用prompt方法傳入標識和參數(shù)(依次對應(yīng)onJsPrompt方法中的message呜袁、defaultValue參數(shù))敌买,以通知java需要使用的方法及對應(yīng)參數(shù)。prompt方法中第一個參數(shù)可以傳送約定好的特定方法標識阶界,prompt方法中第二個參數(shù)可以傳入對應(yīng)的參數(shù)序列虹钮。具體的Javascript代碼如下:
function showHtmlcallJava()
{
var ret = prompt( "1", "param1;param2" );
//ret值即為java傳回的”result”
//根據(jù)返回內(nèi)容作相應(yīng)處理
}
修改點二:移除系統(tǒng)開放的JS接口
對于Android 3.0以上版本,Android系統(tǒng)開放了部分JS接口膘融。因此在這個版本范圍下芙粱,盡管客戶端自身沒有使用addJavascriptInterface方法瓤逼,黑客仍可以透過系統(tǒng)開放的JS接口實施惡意操作椒舵。
針對上述風險,客戶端可通過下面的方法移除風險接口政鼠。具體實施方法如下:
1)使用removeJavascriptInterface方法移除操作系統(tǒng)開放的"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以上系統(tǒng)版本移除問題接口烫堤。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { dealJavascriptLeak(); }
三荣赶、總結(jié)
對于https和http協(xié)議訪問的頁面凤价,開發(fā)過程中須注意棄用存在漏洞的addJavascriptInterface方法,通過使用prompt方法傳參讯壶,完成java與js的交互料仗。同時客戶端須移除系統(tǒng)開放的JS接口,全面規(guī)避WebView漏洞風險伏蚊。
詳細修步驟:
【1】讓JS調(diào)用一個Javascript方法立轧,這個方法中是調(diào)用prompt方法,通過prompt把JS中的信息傳遞過來躏吊,這些信息應(yīng)該是我們組合成的一段有意義的文本氛改,可能包含:特定標識,方法名稱比伏,參數(shù)等胜卤。在onJsPrompt方法中,我們?nèi)ソ馕鰝鬟f過來的文本赁项,得到方法名葛躏,參數(shù)等,再通過反射機制悠菜,調(diào)用指定的方法舰攒,從而調(diào)用到Java對象的方法。
【2】關(guān)于返回值悔醋,可以通過prompt返回回去摩窃,這樣就可以把Java中方法的處理結(jié)果返回到Js中。
【3】我們需要動態(tài)生成一段聲明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字符串造成,它包含了方法名,參數(shù)雄嚣,對象名等晒屎。
3喘蟆,當JS調(diào)用onButtonClick或onImageClick時,就會回調(diào)到Java層中的onJsPrompt方法鼓鲁,我們再解析出方法名蕴轨,參數(shù),對象名骇吭,再反射調(diào)用方法橙弱。
4,window.jsInterface這表示在window上聲明了一個Js對象燥狰,聲明方法的形式是:方法名:function(參數(shù)1棘脐,參數(shù)2)
5,一些思考
以下是在實現(xiàn)這個解決方案過程中遇到的一些問題和思考:
【1】生成Js方法后龙致,加載這段Js的時機是什么蛀缝?
剛開始時在當WebView正常加載URL后去加載Js,但發(fā)現(xiàn)會存在問題目代,如果當WebView跳轉(zhuǎn)到下一個頁面時屈梁,之前加載的Js就可能無效了,所以需要再次加載榛了。這個問題經(jīng)過嘗試在讶,需要在以下幾個方法中加載Js,它們是WebChromeClient和WebViewClient的方法:
· onLoadResource
· doUpdateVisitedHistory
· onPageStarted
· onPageFinished
· onReceivedTitle
· onProgressChanged
目前測試了這幾個地方忽冻,沒什么問題真朗,這里我也不能完全確保沒有問題。
【2】需要過濾掉Object類的方法
由于通過反射的形式來得到指定對象的方法僧诚,他會把基類的方法也會得到遮婶,最頂層的基類就是Object,所以我們?yōu)榱瞬话裧etClass方法注入到Js中湖笨,所以我們需要把Object的公有方法過濾掉旗扑。這里嚴格說來,應(yīng)該有一個需要過濾方法的列表慈省。目前我的實現(xiàn)中臀防,需要過濾的方法有:
"getClass",
"hashCode",
"notify",
"notifyAll",
"equals",
"toString",
"wait",
【3】通過手動loadUrl來加載一段js,這種方式難道js中的對象就不在window中嗎边败?也就是說袱衷,通過遍歷window的對象,不能找到我們通過loadUrl注入的js對象嗎笑窜?
關(guān)于這個問題致燥,我們的方法是通過Js聲明的,通過loadUrl的形式來注入到頁面中排截,其實本質(zhì)相當于把我們這動態(tài)生成的這一段Js直接寫在Html頁面中嫌蚤,所以辐益,這些Js中的window中雖然包含了我們聲明的對象,但是他們并不是Java對象脱吱,他們是通過Js語法聲明的智政,所以不存在getClass之類的方法。本質(zhì)上他們是Js對象箱蝠。
【4】在Android 3.0以下续捂,系統(tǒng)自己添加了一個叫searchBoxJavaBridge_的Js接口,要解決這個安全問題抡锈,我們也需要把這個接口刪除疾忍,調(diào)用removeJavascriptInterface方法。這個searchBoxJavaBridge_好像是跟google的搜索框相關(guān)的床三。
【5】在實現(xiàn)過程中一罩,我們需要判斷系統(tǒng)版本是否在4.2以下,因為在4.2以上撇簿,Android修復(fù)了這個安全問題聂渊。我們只是需要針對4.2以下的系統(tǒng)作修復(fù)。