WebView常見漏洞修復

一、WebView中,主要漏洞有三類

  • 任意代碼執行漏洞
  • 密碼明文存儲漏洞
  • 域控制不嚴格漏洞
    二、具體分析

2.1 WebView任意代碼執行漏洞

出現該漏洞的三個:

  • WebView中addJavascriptInterface()接口
  • WebView 內置導出的 searchBoxJavaBridge_對象
  • WebView 內置導出的 accessibility 和 accessibilityTraversalObject 對象

2.1.1 WebView中addJavascriptInterface()接口

A.漏洞產生原因

JS調用Android的addJavascriptInterface接口進行對象映射:

 webView.addJavascriptInterface(new JSObject(), "myObj");
// 參數1:Android的本地對象
// 參數2:JS的對象
// 通過對象映射將Android中的本地對象和JS中的對象進行關聯,從而實現JS調用Android的對象和方法

原因:在Android早期版本中並沒有對可以訪問的方法做限制,當JS拿到java對象後,就可以利用Java反射機制,調用任意對象的任意方法,如獲取系統類(java.lang.Runtime類)

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

  • WebView 添加 Javascript 對象,並且添加一些權限,比如想要獲取 SD 卡上面的信息就需要 android.permission.WRITE_EXTERNAL_STORAGE

  • JS 中可以遍歷 window對象,找到存在 getClass 方法的對象,再通過反射的機制,得到 Runtime 對象,然後就可以調用靜態方法來執行一些命令,比如訪問文件的命令;

  • 從執行命令後返回的輸入流中得到字符串,比如執行完訪問文件的命令之後,就可以得到文件名的信息了

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);  
        }  
    }  
}  

漏洞解決

4.2以上的版本規定夠被調用的函數必須添加@JavascriptInterface進行註解

4.2以下的版本解決方法

  • 通過重寫WebView中addJavascriptInterface 方法,然後在內部自己維護一個對象映射關係的 Map,當調用 addJavascriptInterface 方法,將需要添加的 JS 接口放入這個 Map 中;
    -每次當 WebView 加載頁面的時候加載一段本地的 JS 代碼:
avascript:(function JsAddJavascriptInterface_(){
//XXX表示注入對象的方法的名字,終端和Web端按照定義的格式去相互調用即可
    if(typeof(window.XXX_js_interface_name)!='undefined'){
            console.log('window.XXX_js_interface_name is exist!!');
        }else{
           window.XXX_js_interface_name={
                   XXX:function(arg0,arg1){
                   //在prompt中返回我們約定的字符串,包含了特定的標識符MyApp,後面包含了一串JSON字符串,它包含了方法名,參數,對象名等。當JS調用XXX方法的時候,就會調用到終端Native層的OnJsPrompt方法中,我們在解析出方法名,參數,對象名等
                     return prompt('MyApp:'+JSON.stringify({obj:'XXX_js_interface_name',func:'XXX_',args:[arg0,arg1]}));
                 },
            };
        }
    })

還有一個問題是什麼時候加載這段 JS 呢,在 WebView 正常加載 URL 的時候去加載它,但是會發現當 WebView 跳轉到下一個頁面時,之前加載的 JS 可能就已經無效了,需要再次加載,所以通常需要在以下幾個方法中加載 JS,這幾個方法分別是 onLoadResource,doUpdateVisitedHistory,onPageStarted,onPageFinished,onReceivedTitle,onProgressChanged。
需要過濾的方法爲Object類中定義的方法

2.2密碼明文存儲漏洞

WebView 默認開啓密碼保存功能 mWebView.setSavePassword(true),如果該功能未關閉,在用戶輸入密碼時,會彈出提示框,詢問用戶是否保存密碼,如果選擇”是”,密碼會被明文保到 /data/data/com.package.name/databases/webview.db 中,這樣就有被盜取密碼的危險,所以需要通過 WebSettings.setSavePassword(false) 關閉密碼保存提醒功能。

2.3域控制不嚴格漏洞

瞭解WebView 中 file 協議的安全性,先看一個Demo, WebViewActivity

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().setJavaScriptEnabled(true);                  
        //webView.getSettings().setAllowFileAccess(false);                   
        //webView.getSettings().setAllowFileAccessFromFileURLs(true);         
        //webView.getSettings().setAllowUniversalAccessFromFileURLs(true); 
        
        Intent i = getIntent();
        String url = i.getData().toString(); //url = file:///data/local/tmp/attack.html 
        webView.loadUrl(url);
    }
 }

當其他應用啓動此 Activity 時, intent 中的 data 直接被當作 url 來加載(假定傳進來的 url 爲 file:///data/local/tmp/attack.html ),通過其他 APP 使用顯式 ComponentName 或者其他類似方式就可以很輕鬆的啓動該 WebViewActivity ,我們知道因爲 Android 中的 sandbox,Android 中的各應用是相互隔離的,在一般情況下 A 應用是不能訪問 B 應用的文件的,但不正確的使用 WebView 可能會打破這種隔離,從而帶來應用數據泄露的威脅,即 A 應用可以通過 B 應用導出的 Activity 讓 B 應用加載一個惡意的 file 協議的 url,從而可以獲取 B 應用的內部私有文件,下面我們着重分析這幾個 API 對 WebView 安全性的影響。

  • setAllowFileAccess
    WebSetting中的方法setAllowFileAccess(boolean allow),Android中的註釋如下:

Enables or disables file access within WebView. File access is enabled by
default. Note that this enables or disables file system access only.
Assets and resources are still accessible using file:///android_asset and
file:///android_res.

這個Api可以設置是否允許WebView使用File協議,Android中默認setAllowFileAccess(true)允許訪問,在File域下,能夠執行任意JavaScript代碼同源策略跨域訪問則能夠對私有目錄文件進行訪問, APP嵌入的WebView未對file:///形式的URL做限制,常見泄露:

  • 使用file 域加載的js能夠使用同源策略跨域訪問導致隱私信息泄露
  • 針對IM類軟件會導致聊天信息、聯繫人等等重要信息泄露
  • 針對瀏覽器類軟件,則更多的是cookie信息泄露
    如果不允許使用 file 協議,則不會存在上述的威脅;

解決方案

對於不需要
setAllowFileAccess(false)來禁止加載file協議類文件

  • setAllowFileAccessFromFileURLs

通過此API可以設置是否允許通過 file url 加載的 Javascript 讀取其他的本地文件,這個設置在 JELLY_BEAN(android 4.1) 以前的版本默認是允許,在 JELLY_BEAN 及以後的版本中默認是禁止的。當 AllowFileAccessFromFileURLs 設置爲 true 時,對應上面的 attack.html 代碼爲:

<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>

當設置成爲 false 時,上述JS的攻擊代碼執行會導致錯誤,表示瀏覽器禁止從 file url 中的 javascript 讀取其它本地文件

  • setAllowUniversalAccessFromFileURLs()

通過此 API 可以設置是否允許通過 file url 加載的 Javascript 可以訪問其他的源,包括其他的文件和 http,https 等其他的源。這個設置在 JELLY_BEAN 以前的版本默認是允許,在 JELLY_BEAN 及以後的版本中默認是禁止的。如果此設置是允許,則 setAllowFileAccessFromFileURLs 不起做用,此時修改 attack.html 的代碼:

<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>

當 AllowFileAccessFromFileURLs 爲 true 時,上述 javascript 可以成功讀取 http://www.so.com 的內容,但設置爲 false 時,上述腳本執行會導致如下錯誤,表示瀏覽器禁止從 file url 中的 javascript 訪問其他源的資源:

漏洞解決方案

setAllowFileAccess(true);                               //設置爲 false 將不能加載本地 html 文件
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
  • setJavaScriptEnabled

通過此API可以設置是否允許WebView使用 JavaScript,默認是不允許,但很多應用,包括移動瀏覽器爲了讓 WebView 執行 http 協議中的 JavaScript,都會主動設置允許 WebView 執行 JavaScript,而又不會對不同的協議區別對待,比較安全的實現是如果加載的 url 是 http 或 https 協議,則啓用 JavaScript,如果是其它危險協議,比如是 file 協議,則禁用 JavaScript。

解決方案:

  • 對於不需要file協議的應用,禁用file協議
setAllowFileAccess(false);                              //設置爲 false 將不能加載本地 html 文件
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
  • 對於需要使用file協議的應用,禁止file協議加載javascript
setAllowFileAccess(true);                             //設置爲 false 將不能加載本地 html 文件
setAllowFileAccessFromFileURLs(false);
setAllowUniversalAccessFromFileURLs(false);
if (url.startsWith("file://") {
    setJavaScriptEnabled(false);
} else {
    setJavaScriptEnabled(true);
}

參考博客:

https://blog.csdn.net/self_study/article/details/54928371
https://www.jianshu.com/p/3a345d27cd42

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章