Android中WebView的JavaScript代碼和本地代碼互動的三種方式

來源:互聯網
上載者:User

標籤:

一、Android中WebView的漏洞分析

最近在開發過程中遇到一個問題,就是WebView使用的時候,還是需要解決之前系統(4.2之前)導致的一個漏洞,雖然現在這個系統版本使用者很少了,但是也不能忽視,關於這個漏洞,這裡就不多做解釋了,可能有的同學早就瞭解了,本來想寫一篇文章詳細介紹一下,但是網上的知識太多了,而且都很詳細,就沒弄了,這裡大致簡單明了的說幾句:

第一、漏洞產生的原因

這個漏洞導致的原因主要是因為Android中WebView中的JS訪問本地方法的方式存在缺陷,我們做過互動的都知道,Android中的互動方式是通過WebView的一個方法:

addJavascriptInterface(new JSObject(), "myObj");

第一個參數:Android本機物件;第二個參數就是JS代碼中需要使用的對象

所以這裡看其實就相當於一個映射關係,把Android中的本機物件和JS中的對象關聯即可。

那麼這裡就存在這樣的一個問題了,在4.2系統之前,JS中通過對象調用的方法無需任何註解約束,那麼就意味著JS中拿到這個對象,就可以調用這個對象中所有的方法,而我們知道Android中的對象有一個公用的方法getClass()方法,而這個方法可以擷取到當前類類型Class,而這個類型有一個很關鍵的方法就是Class.forName,這個方法可以載入一個類,這裡可以載入java.lang.Runtime這個類,而這個類就可以執行本地命令了,那麼就會發生危險了,比如這裡可以執行命令擷取本地裝置的SD卡中的檔案等資訊,非常危險的。

上面可能說的還是有些同學不太瞭解,下面就用一段簡單的JS代碼來瞭解一下:


看到這段JS之後的同學應該好理解了,因為我們Android本地通過WebView進行了對象映射,那麼WebView載入頁面中如果包含這段JS代碼,那麼就會存在這個問題,這裡先遍曆window中所有的對象,然後尋找這個對象是否有getClass方法,有的話就在利用反射調用Runtime類執行具體命令即可。其實這個漏洞也得力於JS中的文法特性,這裡可以看到JS文法非常的靈活。


第二、漏洞修複

當然對於Android4.2之後系統修複了這個漏洞,修複方法也很簡單,加上註解約束:@JavascriptInterface 就是只有加上這個註解的方法才會被JS調用,那麼我們知道getClass是Object類中的,肯定沒有這個註解,那麼上面的JS代碼肯定執行不到了。就這樣解決了這個漏洞。

還有一個問題,就是Android系統預設的會給WebView添加一個JS映射對象:searchBoxJavaBridge_ 這個對象是Android3.0之後預設加上去的,也就是說通過這個對象也是可以操作的上面的代碼的。


二、WebView的JS代碼和本地代碼互動方式

說完了,這個漏洞,下面開始說今天的正題了,為什麼要先介紹這個漏洞呢?原因就是如果要在4.2以下版本中解決這個漏洞的話就需要藉助今天介紹的內容了,首先來看看今天的內容主要是介紹Android中WebView的JS和本地互動的三種方式:

第一種方式:通過addJavascriptInterface方法進行添加對象映射

這種方式不多解釋了,也是Android中最常用的方式,但是這種方式會存在風險就是上面說到的漏洞問題。


這裡定義一個簡單的本機物件,在需要被調用的方法加上約束註解。JS代碼也很簡單:


這種方式的好處在於使用簡單明了,本地和JS的約定也很簡單,就是對象名稱和方法名稱約定好即可,缺點就是存在漏洞問題。



第二種方式:利用WebViewClient介面回調方法攔截url

這種方式其實實現也很簡單,就是我們可以添加WebViewClient回調介面,在shouldOverrideUrlLoading回調方法中攔截url,然後解析這個url的協議,如果發現是我們約定好的協議就開始解析參數執行具體邏輯:


代碼也很簡單,這個方法可以攔截WebView中載入url的過程,得到對應的url,我們就可以通過這個方法,和網頁JS約定好一個協議,看一下JS代碼:


這個JS代碼執行之後,就會觸發本地的shouldOverrideUrlLoading方法,然後進行參數解析,調用指定方法。

這個方法是不會存在第一種方法的漏洞問題,但是細心的同學可以發現,這裡本地和JS之間的約定有點繁瑣,比如要約定好協議,參數名稱等資訊,沒有第一種方式方便。而且最主要的問題是,這個只能主動的調用本地化方法,如果想得到方法的傳回值,只能通過WebView的loadUrl方法去執行JS方法,把傳回值傳遞迴去:mWebView.loadUrl("javascript:clicktworesult("+res+")");


看到這種方式是非常繁瑣的。在Android中也是不提倡使用的。

注意:在iOS中沒有像Android中的第一種方式,他也是為了安全考慮,所以iOS中的互動就是採用的第二種方式,通過攔截url來進行操作的,當時候介紹iOS這部分內容的時候在詳細介紹。


第三種方式:利用WebChromeClient回調介面的三個方法攔截訊息

這個方法的原理其實和第二種方式差不多,只是攔截的介面方法不一樣:


Android中的WebView添加WebChromeClient介面,可以攔截JS中的幾個提示方法,也就是幾種樣式的對話方塊,在JS中有三個常用的對話方塊方法:

1. alert是彈出警告框,在文本裡面加入\n就可以換行。
2. confirm彈出確認框,會返回布爾值,通過這個值可以判斷點擊時確認還是取消。true表示點擊了確認,false表示點擊了取消。
3. prompt彈出輸入框,點擊確認返回輸入框中的值,點擊取消返回null。

那麼這三種對話方塊都是可以在本地攔截到的,那麼第三種方法的原理就是攔截這些方法,得到他們的訊息內容,然後解析即可,比如這裡我們攔截了prompt方法內容:


本地攔截的方法參數說明:


為什麼要攔截prompt方法,因為這個方法可以返回想要的值,而對於alert是無法得到傳回值的,confirm只能得到兩個傳回值。只有prompt方法可以返回各種類型的值,操作最方便。

然後在這個方法中和第二種方法一樣的原理解析訊息內容即可


三、執行結果

下面直接看看上面的三種方式的執行效果:

第一種方式:


第二種方式:


第三種方式:


其中html代碼如下:



四、三種方式總結

好了,到這裡我們就介紹完了Android中WebView的JS和本地互動的三種方式:

第一種方式:是最普遍的用法,方便簡單,但是在4.2系統以下存在漏洞問題

第二種方式:是通過攔截url,解析約定之後的協議調用本地方法,缺點是約束協議比較繁瑣,而且傳回執行之後的傳回值比較麻煩。但是不會存在漏洞問題,而這種方式也是iOS中採用的方式。

第三種方式:其實和第二種方式差不多,只是攔截的方法變了,這裡攔截的是JS中的三種對話方塊方法,而這三種對話方塊方法的區別就在於傳回值問題,alert對話方塊方法沒有傳回值,confirm對話方塊方法只有兩種狀態的傳回值,prompt對話方塊方法可以返回任意類型的傳回值。缺點和第二種方法一樣,協議約定比較繁瑣,但是不會存在漏洞問題。


五、關於4.2以下的WebView漏洞修複策略

最後在來介紹一下文章中開始介紹的漏洞問題,雖然google在4.2之後修複了這個漏洞,但是對於4.2之前的使用者該如何處理這個漏洞呢?這裡主要就是需要藉助第三種方式了,攔截prompt方法,修複步驟很簡單:

1、我們自己顯示一個WebView的封裝器,重寫他的addJavascriptInterface方法,然後在內部自己維護一個對象映射關係Map


2、在WebView載入頁面的方法中構造一段本地JS代碼:


關於這段JS代碼的含義:

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) 

而載入這段JS代碼的時機是什麼時候呢?

剛開始時在當WebView正常載入URL後去載入Js,但發現會存在問題,如果當WebView跳轉到下一個頁面時,之前載入的Js就可能無效了,所以需要再次載入。這個問題經過嘗試,需要在以下幾個方法中載入Js,它們是WebChromeClient和WebViewClient的方法:onLoadResource,doUpdateVisitedHistory,onPageStarted,onPageFinished,onReceivedTitle,onProgressChanged


3、讓JS調用一個Javascript方法,這個方法中是調用prompt方法,通過prompt把JS中的資訊傳遞過來,這些資訊應該是我們組合成的一段有意義的文本,可能包含:特定標識,方法名稱,參數等。在onJsPrompt方法中,我們去解析傳遞過來的文本,得到方法名,參數等,再通過反射機制,調用指定的方法,從而調用到Java對象的方法。


4、關於傳回值,可以通過prompt返回回去,這樣就可以把Java中方法的處理結果返回到Js中。

通過這幾步,就可以簡單的修複漏洞問題,但是還是需要注意幾個問題:

1> 需要過濾掉Object類的方法由於通過反射的形式來得到指定對象的方法,他會把基類的方法也會得到,最頂層的基類就是Object,所以我們為了不把getClass方法注入到Js中,所以我們需要把Object的公有方法過濾掉。這裡嚴格說來,應該有一個需要過濾方法的列表。目前我的實現中,需要過濾的方法有:
"getClass","hashCode","notify","notifyAll","equals","toString","wait",

2> 在Android 3.0以下,系統自己添加了一個叫searchBoxJavaBridge_的Js介面,要解決這個安全問題,我們也需要把這個介面刪除,調用removeJavascriptInterface方法。這個searchBoxJavaBridge_好像是跟google的搜尋方塊相關的。

3> 在實現過程中,我們需要判斷系統版本是否在4.2以下,因為在4.2以上,Android修複了這個安全問題。我們只是需要針對4.2以下的系統作修複。


項目案例:http://download.csdn.net/detail/jiangwei0910410003/9641825


六、總結

在Android中WebView的作用還是舉足輕重的,加上現在很多應用都開始採用網頁版功能,那麼在這個過程中無法避免就是需要JS和本地互動,本文就詳細的介紹了現階段的三種互動方式,每種方式都有缺點和優點,當然最好的方式還是採用系統提供的也就是本文介紹的第一種方式,但是需要修複Android4.2以下存在的漏洞問題即可。


更多內容:點擊這裡

關注公眾號,最新技術乾貨即時推送



Android中WebView的JavaScript代碼和本地代碼互動的三種方式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.