Android:你不知道的 WebView 使用漏洞

Android:你不知道的 WebView 使用漏洞,第1张

Android:你不知道的WebView使用漏洞 前言
  • 现在很多App都内置了网页(HypridApp),比如很多电商平台,淘宝,JD.COM,聚划算等,如下图所示。
  • 以上功能都是通过AndroidWebView实现的,但是WebView的使用存在很多漏洞,很容易导致用户数据泄露等危险,很多人往往会忽略这个问题。
  • 今天我就全面介绍一下AndroidWebView的漏洞以及如何修复
  • 阅读前请先阅读本文:
    Android开发:最全面最易懂的Webview详解
    最全面&最详细的AndroidWebView与JS交互总结

    目录

    1.类型

    在WebView中,有三种主要类型的漏洞:

  • 任意代码执行漏洞
  • 密码明文存储漏洞
  • 松散域控制的漏洞
  • 2.具体分析 2.1WebView任意代码执行漏洞

    此漏洞有三个原因:

  • 在WebView中添加AddJavascriptInterface()接口
  • WebView内置导出的searchBoxJavaBridge_object
  • WebView内置导出的可访问性和accessibilityTraversalObject对象
  • 2.1.1addJavascriptInterface接口引起远程代码执行漏洞 A.漏洞产生原因

    JS调用Android的方式之一是通过addJavascriptInterface接口映射对象:

    webView.addJavascriptInterface(newJSObject(),"myObj"); //参数1:Android的本地对象 //参数2:JS的对象 //通过对象映射将Android中的本地对象和JS中的对象进行关联,从而实现JS调用Android的对象和方法

    所以,漏洞的原因是JS获取Android对象时,可以调用这个Android对象中的所有方法,包括system类(java.lang.Runtime类),从而执行任意代码。

    比如可以执行命令获取本地设备SD卡中的文件等信息,从而造成信息泄露。

    获取具体系统类的描述:(结合Java反射机制)

  • Android中的对象有一个公共方法:getClass();
  • 这个方法可以获取当前的类类型Class。
  • 这个类有一个key方法:Class.forName;
  • 该方法可以加载一个类(可以加载java.lang.Runtime类)。
  • 这个类可以执行本地命令。
  • 以下是攻击的Js核心代码:

    functionexecute(cmdArgs) { //步骤1:遍历window对象 //目的是为了找到包含getClass()的对象 //因为Android映射的JS对象也在window中,所以肯定会遍历到 for(varobjinwindow){ if("getClass"inwindow[obj]){ //步骤2:利用反射调用forName()得到Runtime类对象 alert(obj); returnwindow[obj].getClass().forName("java.lang.Runtime") //步骤3:以后,就可以调用静态方法来执行一些命令,比如访问文件的命令 getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs); //从执行命令后返回的输入流中得到字符串,有很严重暴露隐私的危险。 //如执行完访问文件的命令之后,就可以得到文件名的信息了。 } } }
  • 当一些app通过扫描二维码打开外部网页时,攻击者就可以执行这个js代码进行漏洞攻击。
  • 随着微信和扫货行为的盛行,该漏洞非常危险。
  • B.解决方案 B1.Android4.2版本之后

    在Google的Android版本中,规定用@JavascriptInterface对被调用的函数进行注释,以避免漏洞攻击。

    B2.Android4.2版本之前

    在Android版本之前,使用**blockprompt()**来修复漏洞。
    具体步骤如下:

  • 继承WebView,重写addJavascriptInterface方法,然后内部维护一个地图;对象映射关系的;
  • 把要添加的JS接口放到地图中。

  • WebView每次加载页面前加载一段本地JS代码,原理是: 让JS调用一个Javascript方法:这个方法传递JS中的信息(包括具体标识,方法名等。)到Android通过调用prompt();
  • 在Android的onJsPrompt()中,解析传递的信息,然后通过反射机制调用Java对象方法,实现安全的JS调用Android代码。
  • 关于Android返回给JS的值:Java中方法的处理结果可以通过prompt()返回给Js

    要加载的具体JS代码如下:

    javascript:(functionJsAddJavascriptInterface_(){ //window.jsInterface表示在window上声明了一个Js对象 //jsInterface=注册的对象名 //它注册了两个方法,onButtonClick(arg0)和onImageClick(arg0,arg1,arg2) //如果有返回值,就添加上return if(typeof(window.jsInterface)!='undefined'){ console.log('window.jsInterface_js_interface_nameisexist!!');} else{ window.jsInterface={ //声明方法形式:方法名:function(参数) onButtonClick:function(arg0){ //prompt()返回约定的字符串 //该字符串可自己定义 //包含特定的标识符MyApp和JSON字符串(方法名,参数,对象名等) returnprompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onButtonClick',args:[arg0]})); }, onImageClick:function(arg0,arg1,arg2){ return prompt('MyApp:'+JSON.stringify({obj:'jsInterface',func:'onImageClick',args:[arg0,arg1,arg2]})); }, }; } } )() //当JS调用onButtonClick()或onImageClick()时,就会回调到Android中的onJsPrompt() //我们解析出方法名,参数,对象名 //再通过反射机制调用Java对象的方法 关于该方法的其他细节 细节1:加载上述JS代码的时机
  • 当WebView跳转到下一页时,之前加载的JS可能已经失败。
  • 所以,你通常需要用以下方法加载JS:
  • onLoadResource(); doUpdateVisitedHistory(); onPageStarted(); onPageFinished(); onReceivedTitle(); onProgressChanged(); 细节2:需要过滤掉Object类的方法
  • 最后,因为Android的指定对象的方法是通过反射获得的,所以会同时获得基类的其他方法(最上面的基类就是Object类)。
  • 为了不在JS中注入getClass()之类的方法,我们需要过滤掉Object的常用方法。要过滤的方法列表如下:
  • getClass() hashCode() notify() notifyAl() equals() toString() wait() 总结
  • 在Android4.2之前,需要通过**拦截提示()**来修复漏洞
  • Android4.2以后,只需要用@JavascriptInterface来注释被调用的函数。
  • 关于Android系统的占比,Google公布的数据:截至2017年1月8日,Android4.4占比15%左右,要引起重视。
  • 具体数据如下:

    2.1.2searchBoxJavaBridge_接口引起远程代码执行漏洞 A.漏洞产生原因
  • 在Android3.0下,Android系统默认会通过searchBoxJavaBridge_的JS接口给WebView添加一个Js映射对象:searchBoxJavaBridge_object。
  • 该接口可用于实现远程任意代码。
  • B.解决方案

    删除searchBoxJavaBridge_interface

    //通过调用该方法删除接口 removeJavascriptInterface(); 2.1.3accessibility和accessibilityTraversal接口引起远程代码执行漏洞

    分析和解决方法同上,这里不做过多阐述。

    2.2密码明文存储漏洞 2.2.1问题分析

    WebView默认开启密码保存功能:

    mWebView.setSavePassword(true)`
  • 打开后,当用户输入密码时,会d出一个提示框:询问用户是否保存密码;
  • 如果选择“是”,密码将以明文形式保护在/data/data/com.package.name/databases/webview.db中,因此密码可能会被窃取。
  • 2.2.2解决方案

    关闭密码保存提醒

    WebSettings.setSavePassword(false) 2.3域控制不严格漏洞 2.3.1问题分析

    先看安卓里的WebViewActivity.java:

    publicclassWebViewActivityextendsActivity{ privateWebViewwebView; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_webview); webView=(WebView)findViewById(R.id.webView); //webView.getSettings().setAllowFileAccess(false);(1) //webView.getSettings().setAllowFileAccessFromFileURLs(true);(2) //webView.getSettings().setAllowUniversalAccessFromFileURLs(true);(3) Intenti=getIntent(); Stringurl=i.getData().toString();//url=file:///data/local/tmp/attack.html webView.loadUrl(url); } } /**Mainifest.xml**/ //将该WebViewActivity在Mainifest.xml设置exported属性 //表示:当前Activity是否可以被另一个Application的组件启动 android:exported="true"

    即应用A可以通过应用B输出的Activity让应用B加载一个文件协议的恶意url,从而获取应用B的内部私有文件,这会带来数据泄露的威胁。

    具体来说,当其他应用程序启动此活动时,intent中的数据直接作为url加载(假设传入的url是file://data/local/tmp/attack.html)。其他应用可以通过使用显式ComponentName或其他类似方法轻松启动此WebViewActivity并加载恶意URL。

    下面重点分析WebView中getSettings类的方法对WebView安全性的影响:

  • setAllowFileAccess()
  • setAllowFileAccessFromFileURLs()
  • setAllowUniversalAccessFromFileURLs()
  • 1.setAllowFileAccess() //设置是否允许WebView使用File协议 webView.getSettings().setAllowFileAccess(true); //默认设置为true,即允许在File域下执行任意JavaScript代码

    加载了文件域的Js代码可以使用同源策略跨域访问,导致隐私信息泄露。

  • 同源策略的跨域访问:访问私有目录文件。
  • 对于IM产品来说,聊天信息,联系人等等都是泄露的。
  • 对于浏览器软件,cookie信息泄露。
  • 如果不允许文件协议,就不会有这种威胁;

    webView.getSettings().setAllowFileAccess(true);

    但同时也限制了WebView的功能,使其无法加载本地html文件,如下图所示:

    手机版Chrome默认禁止加载文件协议的文件。

    解决方案:

  • 对于不需要使用文件协议的应用,禁用文件协议;
  • setAllowFileAccess(false);
  • 对于需要使用文件协议的应用,禁止文件协议加载JavaScript。
  • setAllowFileAccess(true); //禁止file协议加载JavaScript if(url.startsWith("file://"){ setJavaScriptEnabled(false); }else{ setJavaScriptEnabled(true); } 2.setAllowFileAccessFromFileURLs() //设置是否允许通过fileurl加载的Js代码读取其他的本地文件 webView.getSettings().setAllowFileAccessFromFileURLs(true); //在Android4.1前默认允许 //在Android4.1后默认禁止

    当AllowFileAccessFromFileURLs()设置为true时,攻击者的JS代码为:

    <script> functionloadXMLDoc() { vararm="file:///etc/hosts"; varxmlhttp; if(window.XMLHttpRequest) { xmlhttp=newXMLHttpRequest(); } xmlhttp.onreadystatechange=function() { //alert("statusis"+xmlhttp.status); if(xmlhttp.readyState==4) { console.log(xmlhttp.responseText); } } xmlhttp.open("GET",arm); xmlhttp.send(null); } loadXMLDoc(); </script> //通过该代码可成功读取/etc/hosts的内容数据

    **解决方案:**SetsetAllowFileAccessFromFileUrls(false);

    当设置为false时,上述JS的攻击代码执行将导致错误,这意味着浏览器禁止从文件url中的javascript读取其他本地文件。

    3.setAllowUniversalAccessFromFileURLs() //设置是否允许通过fileurl加载的Javascript可以访问其他的源(包括http、https等源) webView.getSettings().setAllowUniversalAccessFromFileURLs(true); //在Android4.1前默认允许(setAllowFileAccessFromFileURLs()不起作用) //在Android4.1后默认禁止

    当AllowFileAccessFromFileURLs()设置为true时,攻击者的JS代码为:

    //通过该代码可成功读取http://www.so.com的内容 <script> functionloadXMLDoc() { vararm="http://www.so.com"; varxmlhttp; if(window.XMLHttpRequest) { xmlhttp=newXMLHttpRequest(); } xmlhttp.onreadystatechange=function() { //alert("statusis"+xmlhttp.status); if(xmlhttp.readyState==4) { console.log(xmlhttp.responseText); } } xmlhttp.open("GET",arm); xmlhttp.send(null); } loadXMLDoc(); </script>

    **解决方案:**SetSetallowUniversalAccessfromfileURLs(false);

    4.setJavaScriptEnabled() //设置是否允许WebView使用JavaScript(默认是不允许) webView.getSettings().setJavaScriptEnabled(true); //但很多应用(包括移动浏览器)为了让WebView执行http协议中的JavaScript,都会主动设置为true,不区别对待是非常危险的。

    即使setAllowFileAccessFromfileURLs()和setallowUniversalAccessFromFiles()都设置为false,通过FileURL加载的javascript仍然可以访问其他本地文件:符号链接跨源攻击

    前提是允许文件URL执行javascript,即webview.getsettings()。setjavascriptenabled(true);

    这种攻击之所以奏效,是因为符号链接指向的文件可以通过延迟javascript的执行,用指向其他文件的软链接替换当前文件来读取。具体攻击步骤:

  • 将恶意js代码输出到攻击应用的目录,随机命名为xx.html,修改目录的权限;
  • 修改后睡眠1s完成文件 *** 作;
  • 完成后,通过系统的Chrome应用程序打开xx.html文件。
  • 等待4s让Chrome加载html,最后删除html,用ln-s命令为Chrome的Cookie文件创建一个软连接。
  • 注:在执行这项命令之前,xx.html并不存在;执行该命令后,将生成该文件,并将Cookie文件链接到xx.html。

    然后你可以通过链接访问ChromeCookie。

  • 谷歌没有修复,只是让最新版本的Chrome默认禁用了文件协议,所以这个漏洞在最新版本的Chrome中是不存在的。
  • 然而,日常生活中大量使用WebView的应用程序和浏览器可能会受到该漏洞的影响。利用此漏洞,很容易暴露数据。
  • 如果是文件协议,禁用javascript可以大大降低跨源漏洞对WebView的威胁。

  • 但它不能完全消除跨源文件泄漏。
  • 例子:应用实现下载功能,无法加载的页面会自动下载到sd卡;由于sd卡中的文件可以被所有应用程序访问,所以可以构造一个文件URL指向被攻击应用程序的私有文件,然后使用这个URL启动被攻击应用程序的WebActivity。由于WebActivity无法加载文件,文件将被下载到sd卡,然后可以从sd卡读取文件。
  • 最终解决方案
  • 对于不需要使用文件协议的应用,禁用文件协议;
  • //禁用file协议; setAllowFileAccess(false); setAllowFileAccessFromFileURLs(false); setAllowUniversalAccessFromFileURLs(false);
  • 对于需要使用文件协议的应用,禁止文件协议加载JavaScript。
  • //需要使用file协议 setAllowFileAccess(true); setAllowFileAccessFromFileURLs(false); setAllowUniversalAccessFromFileURLs(false); //禁止file协议加载JavaScript if(url.startsWith("file://"){ setJavaScriptEnabled(false); }else{ setJavaScriptEnabled(true); } 3.总结
  • 本文全面介绍了AndroidWebView的漏洞及其修复方法
  • 希望关于WebView的系列文章对你有所帮助
    Android开发:Webview最全面易懂的详细讲解
    AndroidWebView与JS交互最全面的总结
    教你如何构建AndroidWebview的缓存机制&资源预加载方案
  • 接下来我会继续讲解其他Android开发知识。有兴趣的同学可以继续关注carson_ho的微信微信官方账号[/s2/]

  • 请帮顶/评论点赞!因为你们的鼓励是我写作的最大动力!

    欢迎分享,转载请注明来源:内存溢出

    原文地址: http://outofmemory.cn/zz/755384.html

    (0)
    打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
    上一篇 2022-04-30
    下一篇 2022-04-30

    发表评论

    登录后才能评论

    评论列表(0条)

    保存