JS 與 Native 安全交互淺析,兩種方式實現

js與native的交互

概述

目前所常用的native與js交互有兩種方式,分別為 下面提到的方法1與方法2,這兩種方式各有利弊,在4.2之前使用方法1存在安全問題, 類似與sql的注入漏洞,這是運行時虛擬機的漏洞,暫且這樣理解吧。另外無論哪種方式,都要與頁面開發人員定要協議。

sample運行效果圖

方法1(webClient.loadUrl()):

native:加載web頁面并進行相關setting;

mWebView = (WebView) findViewById(R.id.webview);
        //支持JavaScript腳本
        mWebView.getSettings().setJavaScriptEnabled(true);
        // 加載html
        mWebView.loadUrl("file:///android_asset/web.html");
        //android為flag
        mWebView.addJavascriptInterface(MainActivity.this, "android");

native中調用(帶參&不帶參)js方法實現

//調用js函數
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebView.loadUrl("javascript:javaCallJs()");
            }
        });
        //調用js函數并攜帶參數
        final String param = "'這是參數,注意這個參數的格式'";
        findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 傳遞參數調用
                mWebView.loadUrl("javascript:javaCallJswithParam(" + param + ")");
            }
        });

js響應native方法實現:

<script type="text/javascript">

    function javaCallJs(){
         document.getElementById("content").innerHTML ="<br\>JAVA調用了JS的無參函數";
    }

    function javaCallJswithParam(arg){
         document.getElementById("content").innerHTML =
         ("<br\>"+arg);
    }

</script></code></pre>

web頁面中,調用native方法具體實現

<input type="button" value="調用native方法"
       onclick="window.android.startFunction()"/>
<br/><br/>
<input type="button" value="調用native方法并傳參"
       onclick="window.android.startFunction('native方法被js調用,并傳參')"/>

native中,被調用的方法實現

//由于安全原因 需要加 @JavascriptInterface
    @JavascriptInterface
    public void startFunction() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                new AlertDialog.Builder(MainActivity.this).setMessage("native方法觸發").show();
            }
        });
    }
    @JavascriptInterface
    public void startFunction(final String text) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                new AlertDialog.Builder(MainActivity.this).setMessage(text).show();
            }
        });
    }

上段備注中提到“由于安全原因 需要加@JavascriptInterface”,是指在4.2版本之前的addjavascriptInterface接口引起的漏洞,可能導致惡意網頁通過Js方法遍歷剛剛通過addjavascriptInterface注入進來的類的所有方法從中獲取到getClass方法,然后通過反射獲取到Runtime對象,進而調用Runtime對象的exec方法執行一些操作,惡意的Js代碼如下:

function execute(args) {
    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(args);
        }
    }
}

在Android API Level 17(Android 4.2)之后,可以通過添加@JavascriptInterface這個注解來避免該漏洞,在4.1及之前可以使用方法2 實現native與js之間的交互。

方法2(prompt()$onJsPrompt()/confirm()$onConfirm()/alert()$onAlert()):

繼承WebChromeClient重寫該方法的onJsPrompt()/onConfirm()/onAlert()方法,用到那個方法重寫那個就行,然后設置webView的WebChromeClient為該重寫的類

具體實現

class HarlanWebChromeClient extends WebChromeClient {

    /*此處覆蓋的是javascript中的alert方法。
     *當網頁需要彈出alert窗口時,會執行onJsAlert中的方法
     * 網頁自身的alert方法不會被調用。
     */
    @Override
    public boolean onJsAlert(WebView view, String url, String message,
                             JsResult result) {
        show("onJsAlert");
        result.confirm();
        return true;
    }

    /*此處覆蓋的是javascript中的confirm方法。
     *當網頁需要彈出confirm窗口時,會執行onJsConfirm中的方法
     * 網頁自身的confirm方法不會被調用。
     */
    @Override
    public boolean onJsConfirm(WebView view, String url,
                               String message, JsResult result) {
        show("onJsConfirm");
        result.confirm();
        return true;
    }

    /*此處覆蓋的是javascript中的confirm方法。
     *當網頁需要彈出confirm窗口時,會執行onJsConfirm中的方法
     * 網頁自身的confirm方法不會被調用。
     */
    @Override
    public boolean onJsPrompt(WebView view, String url,
                              String message, String defaultValue,
                              JsPromptResult result) {
        show("onJsPrompt....");
        result.confirm();
        return true;
    }</code></pre> 

然后給webView設置該重寫的類

//設置ChromeClient
mWebView.setWebChromeClient(new HarlanWebChromeClient());

相應的在JS中的具體實現代碼如下

function cfm() {
            confirm("")
        }

        function pmt() {
           prompt("","");
        }

        function onAlert()
        {
            alert("這是網頁中的alert方法,如果重寫了mWebView的onAlert方法,該方法不會執行");
        }

觸發頁面中的js函數,例如:

<p><input type="button" onclick="cfm()" value="Confirm"/></p>
<p><input type="button" onclick="pmt()" value="Prompt"/></p>
<p><input type="button" onclick="onAlert()" value="Alert"/>

實現原理就是在頁面中觸發的方法被webView中設置的WebChromeClient給攔截了,從而執行了WebChromeClient中重寫的onXxx()方法, 沒有執行頁面中相應的onXxx()方法,這是方式相對簡單,而且安全。

 

 

 

來自:https://github.com/ZQiang94/JSInteractsWithNative

 

 本文由用戶 vn439625 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!