彻底解决andorid h5交互!浅谈h5交互和js注入漏洞分析
16lz
2021-01-26
文章分两块,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() 消息
- 说明:
- 常用的拦截是:拦截 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); } } ); }
更多相关文章
- Android(安卓)顶部灰条标题栏不显示的方法
- android事件处理总结--dispatchTouchEvent【转】
- Android(安卓)LayoutInflater.inflate()方法参数详解
- android的触摸机制
- Android短信彩信收发流程(应用层)
- Android中Service的生命周期
- 简单音乐播放实例的实现,Android(安卓)Service AIDL 远程调用服
- [Android(安卓)机制] 使用Ksoap2访问webservie,设置timeout时间
- android 蓝牙模块相关的一些知识了解
随机推荐
- android:layout_gravity和android:gravit
- android:layout_gravity和android:gravit
- android:layout_gravity和android:gravit
- android中线程进程模型
- android:layout_gravity和android:gravit
- android:layout_gravity和android:gravit
- android之常用知识点(一)
- Android真响应式架构——Model层设计
- android:layout_gravity和android:gravit
- 学习培训Android软件工程师之不归路