天天看點

Android中hybrid開發的基礎知識前言簡介作用具體使用Native與JS互動如何避免webview記憶體洩漏建構全面的webview緩存機制 & 資源加載方案webview的那些漏洞

前言

現在很多App裡都内置了Web網頁(Hybrid App),比如說很多電商平台,淘寶、京東、聚劃算等等。那麼這種該如何實作呢?其實這是Android裡一個叫WebView元件實作。下面将圍繞着這點進行詳細的整理說明。

簡介

android控件中的WebView,一個基于webkit引擎、展現web頁面的控件

  1. Android 4.4前:Android Webview在低版本 & 高版本采用了不同的webkit版本的核心
  2. Android 4.4後:直接使用了Chrome核心

作用

  1. 在 Android 用戶端上加載h5頁面
  2. 在本地 與 h5頁面實作互動 & 調用
  3. 其他:對 url 請求、頁面加載、渲染、對話框 進行額外處理。

具體使用

  1. 涉及到的類:
    • Webview類:
      • 建立對象,加載URL,生命周期管理,狀态管理
      • loadUrl(),goBack()等
    • WebSettings類
      • 配置 & 管理WebView
      • 緩存:setCacheMode()
      • 與js互動:setJavascriptEnable()
    • WebViewClient類
      • 處理各種通知 & 請求事件
      • shouldOverrideUrlLoading():打開網頁在webview顯示
      • onPageStarted():載入頁面時
      • onPageFinished():頁面加載結束時
      • onLoadResource():在加載頁面資源時會調用,每一個資源(比如圖檔)的加載都會調用一次。
      • onReceivedError():加載頁面的伺服器出現錯誤時(如404)調用。
      • onReceivedSslError(): 處理https請求,webView預設是不處理https請求的,頁面顯示空白,需要進行如下設定:
      webView.setWebViewClient(new WebViewClient() {    
                  @Override    
                  public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {    
                      handler.proceed();    //表示等待證書響應
                  // handler.cancel();      //表示挂起連接配接,為預設方式
                  // handler.handleMessage(null);    //可做其他處理
                  }    
              });  
      
          // 特别注意:5.1以上預設禁止了https和http混用,以下方式是開啟
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
          mWebView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
          }
                 
    • WebChromeClient類
      • 輔助WebView處理js對話框,網站title,網站icon等
      • onProgressChanged()
      • onReceivedTitle()
      • onJsAlert() 無傳回值 知道了
      • onJsConfirm() 傳回值 true:确認,false:取消
      • onJsPrompt():輸入框,确認:傳回輸入框的内容,取消:傳回null

Native與JS互動

  1. 互動方式:橋梁WebView
    • android調用js代碼
      • 方式一 通過webview的loadUrl()
        • 該方式會引起頁面重新整理
        • 指定url:http:www.baidu.com
        • 指定資源檔案: file:///android_assets/filename.file
        • loadUrl(“javascripr:functionname()”)
      • 方式二:通過webView的evaluateJavaScript()
        • 該方式不會引起頁面重新整理,并且在android4.4之後才可使用
        • 向下相容差
    • js去調用android的代碼
      • 方式一:通過webView的addJavaScriptInterface()進行對象映射
        • 這種方式存在嚴重的漏洞問題
      • 方式二:通過WebViewClient的shouldOverrideUrlLoading()回調攔截url
        • 具體原理:第一步,webview通過webviewclient的回調方法shouldOverrideUrlLoading()攔截url,第二步,解析該url的協定;第三步,如果檢測到内部約定好的協定,則執行業務流程代碼(即js調用android native代碼)
        • 優點: 不存在方式1的漏洞
        • 缺點:js擷取android方法的傳回值複雜。如果js想要得到android方法的傳回值,隻能通過webview的loadUrl()去執行js方法把傳回值傳遞回去
        // Android:MainActivity.java
            mWebView.loadUrl("javascript:returnResult(" + result + ")");
        
            // JS:javascript.html
            function returnResult(result){
                alert("result is" + result);
            }
                   
      • 方式三:通過WebChromeClient的onJsAlert()onJsConfirm()onJsPrompt()方法攔截js對話框資訊
        • 常用的攔截是:onJsPrompt()方法,
        • 因為該方法可以傳回任意類型的值;操作簡便;不存在漏洞;

如何避免webview記憶體洩漏

  1. 不在xml中定義webview,而是在需要的時候再activity中建立,并且使用application context;
  2. 在activity銷毀的時候,先讓webview加載null内容,然後移除webview,再銷毀webview,最後置空
@Override
        protected void onDestroy() {
            if (mWebView != null) {
                mWebView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
                mWebView.clearHistory();

                ((ViewGroup) mWebView.getParent()).removeView(mWebView);
                mWebView.destroy();
                mWebView = null;
            }
            super.onDestroy();
        }
           

建構全面的webview緩存機制 & 資源加載方案

因為在移動端webview存在較為明顯的性能問題,特别突出的是:加載速度慢,流量消耗大。那麼有麼有解決的方案呢?如下:

  1. 存在哪些性能問題?
    • H5頁面加載速度慢
      • 渲染速度
        • js解析效率:js本身解析過程複雜,解析速度不快。并且頁面内涉及較多的js檔案,是以疊加起來使得總的js解析效率低
        • 手機硬體性能:android機型碎片化,導緻手機性能參差不齊。
      • 資源加載慢:H5頁面需要從服務端下載下傳,并存儲在手機記憶體中
        • h5頁面資源多:
        • 網絡請求數量多:每加載一個html頁面,都有url自身的請求,以及頁面中對外部資源的引用也是一個個獨立的http請求;每個請求都是串行
    • 耗費流量:
      • 每次使用h5頁面時, 使用者都需要重新加載頁面
      • 每次加載一個h5頁面,都會産生較多的網絡請求
      • 每個請求都是串行的,這麼多串行導緻流量消耗大
  2. 針對問題,有哪些解決方案:
    1. h5自帶的緩存方案(也是WebView自帶緩存機制):
      • h5頁面加載後會存儲在緩存區域 /data/data/包名/cache 以及 database 其中請求的url記錄儲存在WebViewCache.db 而URL的内容是儲存在WebViewcache檔案夾下
      • android webview 目前除了新的File System緩存機制還不支援,其他都支援
      • 作用:
        • 離線浏覽
        • 提高頁面加載速度,以及減少流量消耗
      • 應用:此處主要講解前端H5的緩存機制(或者緩存模式)
        • 緩存機制:如何将加載過的網頁資料儲存到本地(儲存)
          • 浏覽器 緩存機制
            • 特點:
              • 支援HTTP協定層
              • 緩存檔案需要首次加載後才會産生;
              • 浏覽器緩存的存儲空間有限;
              • 緩存有被清除的可能;
              • 緩存的檔案沒有校驗
            • 根據Http協定頭裡的Cache-Control , Expires,Last-Modified,ETag等字段來控制檔案緩存的機制
            • Cache-Control:用于控制檔案在本地緩存有效時長,伺服器回包:Cache-Control:max-age=600,則表示檔案在本地應該緩存,且有效時長是600秒(從送出請求算起)。在接下來600秒内,如果有請求這個資源,浏覽器不會發出 HTTP 請求,而是直接使用本地緩存的檔案。
            • Expires:與Cache-Control功能相同,即控制緩存的有效時間
              • Expires是HTTP1.0标準中的字段,Cache-Control是HTTP1.1标準中新加的字段
              • 當兩個字段同時出現時,Cache-Control優先級較高
            • Last-Modified:辨別檔案在伺服器上的最新更新時間。
              • 下次請求時,如果檔案緩存過期,浏覽器通過 If-Modified-Since 字段帶上這個時間,發送給伺服器,由伺服器比較時間戳來判斷檔案是否有修改。如果沒有修改,伺服器傳回304告訴浏覽器繼續使用緩存;如果有修改,則傳回200,同時傳回最新的檔案。
            • Etag:功能同Last-Modified,即辨別檔案在伺服器上的最新更新時間
              • 不同的是,Etag的取值是一個對檔案進行辨別的特征字串。
              • 在向伺服器查詢檔案是否有更新時,浏覽器通過If-None-Match 字段把特征字串發送給伺服器,由伺服器和檔案最新特征字串進行比對,來判斷檔案是否有更新:沒有更新回包304,有更新回包200
              • Etag 和 Last-Modified 可根據需求使用一個或兩個同時使用。兩個同時使用時,隻要滿足基中一個條件,就認為檔案沒有更新。
            • 常見用法是:
              • Cache-Control與 Last-Modified 一起使用;控制緩存有效時間
              • Expires與 Etag一起使用;緩存失效後,向伺服器查詢是否有更新
            • 應用場景:
              • 靜态資源檔案的存儲,如js,css,字型,圖檔等,存放在/data/data/包名/…
            • 具體實作:
              • webview内置自動實作,即不需要設定
                • android 4.4後的webview浏覽器核心chrome
                • 浏覽器緩存機制是浏覽器核心的機制,一般都是标準的實作
          • Application cache緩存機制
            • 原理:
              • 以檔案為機關進行緩存,且檔案有一定的更新機制
              • AppCache原理有兩個關鍵點:manifest屬性以及manifest檔案
                <!DOCTYPE html>
                    <html manifest="demo_html.appcache">
                    // HTML 在頭中通過 manifest 屬性引用 manifest 檔案
                    // manifest 檔案:就是上面以 appcache 結尾的檔案,是一個普通檔案檔案,列出了需要緩存的檔案
                    // 浏覽器在首次加載 HTML 檔案時,會解析 manifest 屬性,并讀取 manifest 檔案,擷取 Section:CACHE MANIFEST 下要緩存的檔案清單,再對檔案緩存
                    <body>
                    ...
                    </body>
                    </html>
                
                    // 原理說明如下:
                    // AppCache 在首次加載生成後,也有更新機制。被緩存的檔案如果要更新,需要更新 manifest 檔案
                    // 因為浏覽器在下次加載時,除了會預設使用緩存外,還會在背景檢查 manifest 檔案有沒有修改(byte by byte)
                    發現有修改,就會重新擷取 manifest 檔案,對 Section:CACHE MANIFEST 下檔案清單檢查更新
                    // manifest 檔案與緩存檔案的檢查更新也遵守浏覽器緩存機制
                    // 如使用者手動清了 AppCache 緩存,下次加載時,浏覽器會重新生成緩存,也可算是一種緩存的更新
                    // AppCache 的緩存檔案,與浏覽器的緩存檔案分開存儲的,因為 AppCache 在本地有 5MB(分 HOST)的空間限制
                
                
                           
              • 特點: 友善建構web app的緩存
              • 應用場景:存儲靜态檔案(js,css,字型檔案)
                • 應用場景同浏覽器緩存機制
                • 但appcache是對浏覽器緩存機制的補充,不是替代
              • 具體實作
              // 通過設定WebView的settings來實作
              WebSettings settings = getSettings();
              
              String cacheDirPath = context.getFilesDir().getAbsolutePath()+"cache/";
              settings.setAppCachePath(cacheDirPath);
              // 1. 設定緩存路徑
              
              settings.setAppCacheMaxSize(20*1024*1024);
              // 2. 設定緩存大小
              
              settings.setAppCacheEnabled(true);
              // 3. 開啟Application Cache存儲機制
              
              // 特别注意
              // 每個 Application 隻調用一次 
              WebSettings.setAppCachePath() 和WebSettings.setAppCacheMaxSize()
                         
          • DOM Storage緩存機制
            • 原理:
              • 通過存儲字元串的key-value來提供
              • Dom storage分為session storage和local storage
                • session storage:具備臨時性,即存儲與頁面相關的資料,它在頁面關閉後無法使用
                • local storage:具備持久性,即儲存的資料在頁面關閉後也可以使用
            • 特點
              • 存儲空間大(5MB):存儲空間對于不同浏覽器不同,如cookie才4kb
              • 存儲安全,便捷:DOM storage存儲的資料在本地,不需要經常和伺服器進行互動
              • 不像cookie每次請求一次頁面,都會向伺服器發送網絡請求
            • 應用場景
              • 存儲臨時,簡單的資料;
                • dom storage 機制類似于android的sharedPreference機制
            • 具體實作:
          // 通過設定

          WebView

          Settings

          類實作

          WebSettings settings = getSettings();

          settings.setDomStorageEnabled(true);
                // 開啟DOM storage
            ```
                     
          • Web SQL Database緩存機制
            • 原理:
              • 基于SQL的資料庫存儲機制
            • 特點:
              • 充分利用資料庫的優勢,可友善對資料進行增删改查
            • 應用場景:
              • 存儲适合資料庫的結構化資料
            • 具體實作
            // 通過設定WebView的settings實作
            WebSettings settings = getSettings();
            
            String cacheDirPath = context.getFilesDir().getAbsolutePath()+"cache/";
            settings.setDatabasePath(cacheDirPath);
            // 設定緩存路徑
            
            settings.setDatabaseEnabled(true);
            // 開啟 資料庫存儲機制
                       
            • 特别說明:
              • Web SQL Database存儲機制不再推薦使用
              • 取而代之的是IndexeDB緩存機制
          • Indexed Database緩存機制
            • 原理:
              • 類似NoSQL資料庫,通過存儲字元串的key-value對來提供
              • 類似Dom storage 存儲機制的key-value存儲方式
            • 特點:
              • 功能強大,使用簡單
                • 通過資料庫的事物transation機制進行資料操作
                • 可對對象的任意屬性生成索引,友善查詢
              • 存儲空間大:
                • 較大存儲空間,預設推薦250MB(以host區分),比Dom storage的5MB要大的多
              • 使用靈活:
                • 以key-value的方式存儲對象,可以是任何類型值或對象,包括二進制
                • 異步api調用,避免造成等待而影響體驗
            • 應用場景:
              • 存儲複雜,資料量大的結構化資料
            • 具體實作:
            // 通過設定WebView的settings實作
            WebSettings settings = getSettings();
            
            settings.setJavaScriptEnabled(true);
            // 隻需設定支援JS就自動打開IndexedDB存儲機制
            // Android 在4.4開始加入對 IndexedDB 的支援,隻需打開允許 JS 執行的開關就好了。
                       
          • File System 緩存機制(H5頁面新加入的緩存機制,雖然android webview暫時不支援,但會進行簡單介紹)
            • 原理:
              • 為H5頁面的資料,提供一個虛拟的檔案系統
                • 可以進行檔案的建立,讀寫,删除,周遊等,就想native app通路本地檔案系統一樣
                • 虛拟的檔案系統是運作在沙盒中
                • 不同web app的虛拟檔案系統是互相隔離的,虛拟檔案系統與本地檔案系統也是互相隔離的
              • 虛拟檔案系統提供兩種類型的存儲空間:臨時 & 持久
                • 臨時:由浏覽器自動配置設定,但可能被浏覽器回收
                • 持久:需要顯示申請;自己管理;
            • 特點:
              • 可存儲資料體積較大的二進制資料
              • 可預加載資源檔案
              • 可直接編輯檔案
            • 應用場景
              • 通過檔案系統,管理資料
            • 具體使用
              • 由于File System是由H5新加入的緩存機制,是以android webview暫不支援
        • 緩存模式:
          • 定義:加載網頁時webview如何讀取之前儲存到本地的網頁緩存(讀取)。
          • webview自帶緩存模式四種
            • LOAD_CACHE_ONLY : 不使用網絡,隻讀取本地緩存資料
            • LOAD_NO_CACHE: 不使用緩存,隻從網絡擷取資料
            • LOAD_DEFAULT:預設,根據Cache-Control決定是否從網絡上擷取資料
            • LOAD_CACHE_ELSE_NETWORK:隻要本地有,無論是否過期,或者no-cache,都使用緩存資料
      • 資源預加載:
        • 定義:提前加載将需要使用的H5頁面,即 提前建構緩存;使用時直接取過來,而不是在需要的時候才去加載
        • 具體實作:
          • 預加載webview對象 & 預加載H5資源
        • 預加載webview對象:
          • 首次使用 WebView對象
            • 原因:
              • 首次初始化webview會比第2次初始化慢很多
              • 初始化後,及時webview已釋放,但是一些多個webview共用的全局服務/資源對象仍未釋放
              • 第二次初始化時,不需要再生成,進而變快
            • 實作思路:
              • 應用啟動時就初始化1個全局的webview對象
              • 當使用者需加載H5頁面時,則直接使用該WebView對象加載并顯示
            • 具體實作:
              • 在android的BaseApplication中初始化一個webView對象,放入webview對象池
          • 後續使用Webview對象
            • 原因:
              • 多次建立webview對象會消耗很多時間以及資源
            • 實作思路:
              • 自身建構webview複用池
              • 當使用者需使用webview加載H5頁面時,直接從池中擷取webview對象
            • 具體實作:
              • 采用2個/多個webview的複用,而不需要每次打開H5都需要重新建構
        • 預加載h5資源
          • 原理:
            • 在應用啟動,初始化第一個webview對象的時候,直接開始網絡請求加載h5頁面
            • 後續需要打開這些H5頁面時就直接從該本地對象中擷取
              • 事前加載常用的H5頁面資源(加載後就有緩存了)
              • 此方法雖然不能減少webview初始化時間,但是資料請求和webview初始化可以并行進行,總體的頁面加載時間就縮短了;縮短總體的頁面加載時間
          • 具體實作:
            • 在android的BaseApplication裡初始化一個webview對象,(用于加載常用的H5頁面資源);當需要使用這些頁面時再取出來直接使用
          • 應用場景:
            • 對于android webview的首頁建議使用這種方案,能有效提高首頁加載的效率。
      • 自身建構緩存
        • 除了使用android webview自身的緩存機制外,還可以自己針對某一需求場景建構緩存機制。
        • 背景:H5頁面有一些更新頻率低,常用&固定的靜态資源檔案,如js,css檔案,圖檔
        • 沖突:每次重新加載會浪費很多資源(時間&流量)
        • 解決方案:
          • 通過攔截H5頁面的資源網絡請求,若資源相同,則直接從本地讀取資源,而不需要發送網絡請求到伺服器擷取
        • 實作步驟:
          • 提前将更新頻率低,常用&固定的H5靜态資源檔案存放到本地
          • 攔截H5頁面的網絡請求,過濾相關資源的網絡請求
          • 如果檢測到本地有相同資源,則讀取本地的

webview的那些漏洞

類型

  1. 任意代碼執行漏洞
    • addJavascriptInterface()
    • webview内置到處的searchBoxJavaBridge 對象
    • webview内置導出的accesssibility和accessibilityTraversalObject對象
  2. 密碼明文存儲漏洞
  3. 域控制不嚴格漏洞

具體分析

  1. 任意代碼執行漏洞
    • addJavascriptInterface()接口
      • 漏洞産生原因:
      webView.addJavascriptInterface(new JSObject(), "myObj");
      // 參數1:Android的本地對象
      // 參數2:JS的對象
      // 通過對象映射将Android中的本地對象和JS中的對象進行關聯,進而實作JS調用Android的對象和方法
      是以,漏洞産生的原因是:當js拿到android這個對象後,進而實作js調用android對象中所有的方法,包括系統類,進而進行任意代碼執行。如可以執行指令擷取本地裝置的sd卡中的檔案等資訊進而造成資訊洩露。
                 
      • 具體擷取系統類的描述(結合java反射機制)
        • android中的對象有一公共的方法:getClass();
        • 該方法可以擷取到目前類 類型Class
        • 該類有一關鍵的方法:Class.forName()
        • 該方法可以加載一個類(java.lang.Runtime)
        • 而且該類是可以執行本地指令的
      • js攻擊核心代碼
        function execute(cmdArgs)  
            {  
                // 步驟1:周遊 window 對象
                // 目的是為了找到包含 getClass ()的對象
                // 因為Android映射的JS對象也在window中,是以肯定會周遊到
                for (var obj in window) {  
                    if ("getClass" in window[obj]) {  
        
                // 步驟2:利用反射調用forName()得到Runtime類對象
                        alert(obj);          
                        return  window[obj].getClass().forName("java.lang.Runtime")  
        
                // 步驟3:以後,就可以調用靜态方法來執行一些指令,比如通路檔案的指令
            getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);  
        
            // 從執行指令後傳回的輸入流中得到字元串,有很嚴重暴露隐私的危險。
            // 如執行完通路檔案的指令之後,就可以得到檔案名的資訊了。
                    }  
                }  
            }   
                   
      • 當一些 APP 通過掃描二維碼打開一個外部網頁時,攻擊者就可以執行這段 js 代碼進行漏洞攻擊。在微信盛行、掃一掃行為普及的情況下,該漏洞的危險性非常大
      • 具體解決方案:
        • 方案一:在Android 4.2 版本中規定對被調用的函數以 @JavascriptInterface進行注解進而避免漏洞攻擊
        • 方案二:在Android 4.2版本之前采用攔截prompt()進行漏洞修複。
          • 具體步驟:繼承WebView,重寫addJavascriptInterface()方法,然後在内部自己維護一個對象映射關系的Map;将需要添加的js接口放入該map中
          • 每次當WebView加載頁面前,加載一段本地代碼的js代碼。原理是:
            • 讓js調用一JavaScript方法:該方法是通過調用prompt()把js中的資訊(含有特點辨別,方法名稱,參數等)傳遞到android端;
            • 在android的onJsPrompt()中,解析傳遞過來的資訊,再通過反射機制調用java對象的方法,這樣實作安全的js調用android代碼。
            • 關于android傳回給js的值:可以通過prompt()把java中方法的處理結果傳回到js中
    • webview内置到處的searchBoxJavaBridge_對象
      • 原因:在Android 3.0以下,Android系統會預設通過searchBoxJavaBridge_的Js接口給 WebView 添加一個JS映射對象:searchBoxJavaBridge_對象。該接口可能被利用,實作遠端任意代碼。
      • 解決方案:删除searchBoxJavaBridge_的js接口
      // 通過調用該方法删除接口
          removeJavascriptInterface();
                 
    • webview内置導出的accesssibility和accessibilityTraversalObject對象
      • 同searchBoxJavaBridge_對象
  2. 密碼明文存儲漏洞
    • WebView預設開啟密碼儲存功能 :mWebView.setSavePassword(true)`
    • 開啟後,在使用者輸入密碼時,會彈出提示框:詢問使用者是否儲存密碼;如果選擇”是”,密碼會被明文保到 /data/data/com.package.name/databases/webview.db 中,這樣就有被盜取密碼的危險
    • 解決方案:關閉密碼儲存提醒,WebSettings.setSavePassword(false)
  3. 域控制不嚴格漏洞
    • 即 A 應用可以通過 B 應用導出的 Activity 讓 B 應用加載一個惡意的 file 協定的 url,進而可以擷取 B 應用的内部私有檔案,進而帶來資料洩露威脅。。具體:當其他應用啟動此 Activity 時, intent 中的 data 直接被當作 url 來加載(假定傳進來的 url 為 file:///data/local/tmp/attack.html ),其他 APP 通過使用顯式 ComponentName 或者其他類似方式就可以很輕松的啟動該 WebViewActivity 并加載惡意url。
    • 下面我們着重分析WebView中getSettings類的方法對 WebView 安全性的影響:
      • setAllowFileAccess()
      // 設定是否允許 WebView 使用 File 協定
          webView.getSettings().setAllowFileAccess(true);     
          // 預設設定為true,即允許在 File 域下執行任意 JavaScript 代碼;
          // 如果是false,則不會存在上述的威脅,但同時也限制了 WebView 的功能,使其不能加載本地的 html 檔案
                 
      使用 file 域加載的 js代碼能夠使用進行同源政策跨域通路,進而導緻隐私資訊洩露
      1. 同源政策跨域通路:對私有目錄檔案進行通路
      2. 針對IM類産品,洩漏的是聊天資訊,以及聯系人等
      3. 針對浏覽器類軟體,洩漏的是cookie資訊
      4. 解決該問題方案:則需要對不使用file協定的業務啟用,對使用file協定的禁用
      // 禁止 file 協定加載 JavaScript
          if (url.startsWith("file://") {
              setJavaScriptEnabled(false);
          } else {
              setJavaScriptEnabled(true);
          }
                 
      • setAllowFileAccessFromFileURLs():設定是否允許通過 file url 加載的 Js代碼讀取其他的本地檔案
        當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 的内容資料
                   
        • 解決方案:設定setAllowFileAccessFromFileURLs(false);當設定成為 false 時,上述JS的攻擊代碼執行會導緻錯誤,表示浏覽器禁止從 file url 中的 javascript 讀取其它本地檔案。
      • setAllowUniversalAccessFromFileURLs(): 設定是否允許通過 file url 加載的 Javascript 可以通路其他的源(包括http、https等源)。// 在Android 4.1前預設允許(setAllowFileAccessFromFileURLs()不起作用)// 在Android 4.1後預設禁止
        • 當AllowFileAccessFromFileURLs()被設定成true時,攻擊者的JS代碼是:
            // 通過該代碼可成功讀取 http://www.so.com 的内容
                <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);
                     
      • setJavaScriptEnabled():設定是否允許 WebView 使用 JavaScript(預設是不允許).但很多應用(包括移動浏覽器)為了讓 WebView 執行 http 協定中的 JavaScript,都會主動設定為true,不差別對待是非常危險的。