彻底解决andorid h5交互!浅谈h5交互和js注入漏洞分析

文章分两块,js调用andorid代码,android代码调用js

参考的博文http://blog.csdn.net/carson_ho/article/details/64904691

这也许是功能最强大的Android与Javascript交互开源库

前提 打开js交互 webview.getSetting().setJavaScriptEnable(true);

一:android调用js代码

说明:主要有两种方式,

方式1: 4.4系统以前
//需要另外开启线程
mWebView.post(new Runnable() {
//                    @Override
                    public void run() {
                  // 调用javascript的callJS()方法   ,,用于4.4以下,缺点:该方法会使页面再次刷新,且无法获取返回值
                        mWebView.loadUrl("javascript:callJS()");
                    }
                });
方式2: 4.4系统以上
//4.4以上可用,优点:不会使页面再次刷新,且可以获取返回值
                    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
                        @Override
                        public void onReceiveValue(String value) {
                            //此处为 js 返回的结果
                        }
                    });

综合使用:

if(Build.VERSION.SDK_INT<19){
                    mWebView.post(new Runnable() {
//                    @Override
                    public void run() {
                  // 调用javascript的callJS()方法   ,,用于4.4以下,缺点:该方法会使页面再次刷新,且无法获取返回值
                        mWebView.loadUrl("javascript:callJS()");
                    }
                });
                }else{
                  //4.4以上可用,优点:不会使页面再次刷新,且可以获取返回值
                    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
                        @Override
                        public void onReceiveValue(String value) {
                            //此处为 js 返回的结果
                        }
                    });
                }

二,js调用android代码

一: 通过addJavascriptInterface 接口

通过webView.addJavascriptInterface(new JsObject(), "injectedObject");接口

参考博文

4.2版本以前,我们一般是这么做的
//随便创建一个类
class JsObject {  
    //新建一个js要调用的方法  
    public String toString() { return "injectedObject"; }  
 }  
 //将该类的对象注入到js代码中
 webView.addJavascriptInterface(new JsObject(), "injectedObject");
  • [ 该方式有个致命漏洞,就是当js端得到我们注入的类对象的时候,可以通过类对象得到Java.lang.Runtime类,这样js就可以通过adb命令修改前端程序,比如文件修改等]
  • 关于漏洞分析请看这篇文章
  • 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);  

// 从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。
// 如执行完访问文件的命令之后,就可以得到文件名的信息了。
        }  
    }  
}  
4.2版本后:google修复了该漏动,虽有注入的类对象都必须添加@JavascriptInterface 注解,以代码只有该类的注解方法可以被js调用
webview.getSetting().setJavaScriptEnable(true);  
class JsObject {  
//js要调用的方法必须添加注解
    @JavascriptInterface  
    public String toString() { return "injectedObject"; }  
 }  
 webView.addJavascriptInterface(new JsObject(), "injectedObject");  
二.使用:

注意: 以下下代码必须要在loadurl前调用,也就是说需要先注入,再加载网页,否者无效

 注入该对象,第二个参数则是js中要用的该对象的变量名
 mWebView.addJavascriptInterface(new AndoridJs(), "test");//AndroidtoJS类对象映射到js的test对象

html代码



    
    Carson
    


//点击按钮则调用callAndroid函数



二:通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url(无方式一存在的漏洞)

示例html


   
      
      Carson_Ho

     



   
     
   

调用 :注意要和html上的沟通协议一样
// 复写WebViewClient类的shouldOverrideUrlLoading方法
mWebView.setWebViewClient(new WebViewClient() {
                                      @Override
                                      public boolean shouldOverrideUrlLoading(WebView view, String url) {

                                          // 步骤2:根据协议的参数,判断是否是所需要的url
                                          // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
                                          //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

                                          Uri uri = Uri.parse(url);                                 
                                          // 如果url的协议 = 预先约定的 js 协议
                                          // 就解析往下解析参数
                                          if ( uri.getScheme().equals("js")) {

                                              // 如果 authority  = 预先约定协议里的 webview,即代表都符合约定的协议
                                              // 所以拦截url,下面JS开始调用Android需要的方法
                                              if (uri.getAuthority().equals("webview")) {

                                                 //  步骤3:
                                                  // 执行JS所需要调用的逻辑
                                                  System.out.println("js调用了Android的方法");
                                                  // 可以在协议上带有参数并传递到Android上
                                                  HashMap params = new HashMap<>();
                                                  Set collection = uri.getQueryParameterNames();

                                              }

                                              return true;
                                          }
                                          return super.shouldOverrideUrlLoading(view, url);
                                      }
                                  }
        );

++该方式缺点:JS获取Android方法的返回值复杂。若要返回给js值,就必须再通过andorid调用js的方法传递参数过去++

方式二 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

  1. 说明:
  2. 常用的拦截是:拦截 JS的输入框(即prompt()方法)
    因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值
html示例:

   
      
      Carson_Ho

     



   
     
   

使用:
// 设置允许JS弹窗
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

// 先加载JS代码
        // 格式规定为:file:///android_asset/文件名.html
        mWebView.loadUrl("file:///android_asset/javascript.html");


        mWebView.setWebChromeClient(new WebChromeClient() {
                                        // 拦截输入框(原理同方式2)
                                        // 参数message:代表promt()的内容(不是url)
                                        // 参数result:代表输入框的返回值
                                        @Override
                                        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                                            // 根据协议的参数,判断是否是所需要的url(原理同方式2)
                                            // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
                                            //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

                                            Uri uri = Uri.parse(message);
                                            // 如果url的协议 = 预先约定的 js 协议
                                            // 就解析往下解析参数
                                            if ( uri.getScheme().equals("js")) {

                                                // 如果 authority  = 预先约定协议里的 webview,即代表都符合约定的协议
                                                // 所以拦截url,下面JS开始调用Android需要的方法
                                                if (uri.getAuthority().equals("webview")) {

                                                    //
                                                    // 执行JS所需要调用的逻辑
                                                    System.out.println("js调用了Android的方法");
                                                    // 可以在协议上带有参数并传递到Android上
                                                    HashMap params = new HashMap<>();
                                                    Set collection = uri.getQueryParameterNames();

                                                    //参数result:代表消息框的返回值(输入值)
                                           //注意记得把弹窗消费掉,否者下个页面可能会被卡住         result.confirm("js调用了Android的方法成功啦");
                                                }
                                                return true;
                                            }
                                            return super.onJsPrompt(view, url, message, defaultValue, result);
                                        }

// 通过alert()和confirm()拦截的原理相同,此处不作过多讲述

                                        // 拦截JS的警告框
                                        @Override
                                        public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                                            return super.onJsAlert(view, url, message, result);
                                        }

                                        // 拦截JS的确认框
                                        @Override
                                        public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
                                            return super.onJsConfirm(view, url, message, result);
                                        }
                                    }
        );


            }

你可能感兴趣的:(彻底解决andorid h5交互!浅谈h5交互和js注入漏洞分析)