Android之WebView 使用注意点 JS注入漏洞问题 内存优化【五】

老早之前就想总结下Webview相关的知识点了,因为互联网大潮中,很多APP都会使用到Webview,像那些不计其数的电商APP,无一例外的使用Webview;或者一些非电商APP中的像广告页面,注册协议页面都会用到;最后因为一些事情拖到现在才做,感觉事情真不能拖,越往后推越做不了,罪过罪过。

怎么总结Webview呢

1.简单介绍

2.WebView/WebViewClient/WebChromeClient api介绍

3.简单使用

4.JS调用Android本地

5.Android调用JS方法

6.缓存处理及性能优化

7.webview使用注意点


webview系列文章

Android之WebView/WebViewClient/WebChromeClient简介 API详述 【一】

Android之WebView/WebViewClient/WebChromeClient 使用样例 【二】

Android之WebView Android调用JS方法 JS调用Android方法 【三】

Android之WebView 缓存处理 性能优化【四】

Android之WebView 使用注意点 JS注入漏洞问题 内存优化【五】


7.webview使用注意点

现在市面上的APP多多少少都是带有WebView的,即混合式APP,并且很多主流的APP还是以WebView为主,Native为辅;它的优点确实很多,但是其中一个很重要的就是内存问题,一个手机终端,运行内存就这么多,WebView稍微不注意,就造成了内存泄露,运行时间长了APP就GG了。那在平时的开发中如何避免呢。


1.将WebView放在一个独立的进程中,与应用程序主进程隔离开

这个方法对于解决WebView造成的内存泄露是非常好的一个方法,即使这个进程挂了,也不会影响app主进程的使用。

先在AndroidManifest里进行注册

<activity
    android:name=".WebViewAct"
    android:launchMode="singleInstance"
    android:process=":remote">
    <intent-filter >
        <action android:name="android.intent.action.webview"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

这里通过process属性将这个webview所依附的activity放到另一个进程中,

但是这里就涉及到进程间如何通信,数据怎么传递,请转到我之前的一篇文章里

Android四大组件之Service 远程服务解析,通过AIDL达到进程间通信交换基础数据

Android四大组件之Service 远程服务 通过AIDL进行进程间复杂类型数据交换

把这个远程服务与这个activity放于同一个进程中,间接地这个activity与主进程的activity就能通信了

然后启动这个activity就行了

Intent intent = new Intent();
intent.setAction("android.intent.action.webview");
startActivity(intent);

2.如果在与应用在同一个进程中,那就通过new的方法去添加webview,而不是在xml里添加,且Context使用全局的context,避免造成当前Activity的引用滥用

mRootView = (RelativeLayout) findViewById(R.id.content);
mWebView = new WebView(getApplicationContext());
mRootView.addView(mWebView);

在销毁的时候清除内存

@Override
    public void onDestroy() {

        if (mWebview != null) {
            mWebview.setWebViewClient(null);
            mWebview.setWebChromeClient(null);
            mWebview.removeJavascriptInterface("mango");
//            mWebview.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
            mWebview.clearHistory();

            ((ViewGroup) mWebview.getParent()).removeView(mWebview);
            mWebview.destroy();
            mWebview = null;
        }
        super.onDestroy();
    }

3.说完内存使用的注意点后,看一下Webview中JS注入的漏洞问题。当我们使用addJavaScriptInterface注入Java对象的时候,在android4.2版本以下会产生严重的漏洞

*.WebView 中addJavascriptInterface()引起远程代码执行漏洞

*.WebView 中内置导出的 “searchBoxJavaBridge_” Java Object 可能被利用,实现远程任意代码

主要原因就是当我们执行这个方法后

addJavascriptInterface(new JSInterface(), "mango");

在JS中拿到这个对象,结合反射, 就可以调用这个类的所有方法,包括获取系统类,如Runtime类,这样就可以做很多不为人知的事情了,比如通过Runtime类执行命令获取本地文件信息。

当我们在大街上碰到很多那种只要你用手机扫一扫,就可以免费领取奖品等活动,这时候你的手机加载一个外部网页,就可以利用漏洞进行JS攻击,很危险的。

那怎么解决呢:

a.android4.2以后,google做了修正,只需在被js调用的方法前加上@JavascriptInterface注解,这样就能避免调用到其它方法。

b.android4.2以前,比较麻烦,尽量不要使用addJavaSciptInterface方法了,通过其它方法与js进行交互

c.当不使用webview后记得

mWebview.removeJavascriptInterface("mango");

d.在创建Webview以后,android4.2以下会自动添加几个js映射接口,这几个接口也会存在问题,我们remove掉

mWebview.removeJavascriptInterface("searchBoxJavaBridge_");
mWebview.removeJavascriptInterface("accessibility");
mWebview.removeJavascriptInterface("accessibilityTraversal");

e.在平时使用的时候关闭密码保存提醒,因为开启后用户输入密码后会弹出框提醒是否保存,如果是就会被保存到

/data/data/com.package.name/databases/webview.db 中,很明显有被盗取的风险

mSetting.setSavePassword(false);

4.webview默认是允许使用File协议的

如下面几个设置

mSetting.setAllowFileAccess(true);
mSetting.setAllowFileAccessFromFileURLs(true);
mSetting.setAllowUniversalAccessFromFileURLs(true);

对于第一个设置,使用file域加载的本地html文件中js代码,可能会导致很多信息泄露

一般情况下我们选择禁用,或者不禁用,但是需要禁止使用js交互功能

//是否允许访问文件,默认允许。注意,这里只是允许或禁止对文件系统的访问,
// Assets 和 resources 文件使用file:///android_asset和file:///android_res仍是可访问的
mSetting.setAllowFileAccess(true);
// 禁止 file 协议加载 JavaScript
if (mUrl.startsWith("file://")) {
    mSetting.setJavaScriptEnabled(false);
} else {
    mSetting.setJavaScriptEnabled(true);
}
对于第二种情况

// 在Android 4.1前默认允许 在Android 4.1后默认禁止
// 设置是否允许通过 file url 加载的 Js代码读取其他的本地文件
// 是否允许运行在一个URL环境(the context of a file scheme URL)中的JavaScript访问来自其他URL环境的内容,
// 为了保证安全,应该不允许。也请注意,这项设置只影响对file schema 资源的JavaScript访问,
// 其他形式的访问,例如来自图片HTML单元的访问不受影响。
// 为了防止相同的域策略(same domain policy)对ICE_CREAM_SANDWICH以及更老机型的侵害,应该显式地设置此值为false。
mSetting.setAllowFileAccessFromFileURLs(false);

对于第三种情况

// 在Android 4.1前默认允许 在Android 4.1后默认禁止
// 设置是否允许通过 file url 加载的Js代码 可以访问其他的源(包括http、https等源)
// 是否允许运行在一个file schema URL环境下的JavaScript访问来自其他任何来源的内容,包括其他file schema URLs.
// 参见setAllowFileAccessFromFileURLs(boolean),为了确保安全,应该设置为不允许,
// 注意这项设置只影响对file schema 资源的JavaScript访问,其他形式的访问,例如来自图片HTML单元的访问不受影响。
// 为了防止相同的域策略(same domain policy)对ICE_CREAM_SANDWICH以及更老机型的侵害,
// 应该显式地设置此值为false。ICE_CREAM_SANDWICH_MR1 以及更老的版本此默认值为true,JELLY_BEAN以及更新版本此默认值为false
mSetting.setAllowUniversalAccessFromFileURLs(false);

5.    版本问题

android版本非常多,很多api在高级版本以后就不能使用了,这就需要我们在使用的时候多进行版本的判断,然后决定使用什么方法。

* 你可能遇到onPageStarted和onPageFinished回调不成对,可能你想着加loading动画,在onPageStarted开始,在onPageFinished结束;如果回调不成对,就很麻烦了;这时候可以在onProgressChanged中判断,当进度达到100%后表示加载结束。

* 还有跨域cookie读取的问题,cookie是什么呢:

cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能

Cookie主要用于以下三个方面:

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

Cookie曾一度用于客户端数据的存储,因当时并没有其它合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie渐渐被淘汰。由于服务器指定Cookie后,浏览器的每次请求都会携带Cookie数据,会带来额外的性能开销(尤其是在移动环境下)。新的浏览器API已经允许开发者直接将数据存储到本地,如使用 Web storage API (本地存储和会话存储)或 IndexedDB 。

跨域读取cookie就是你浏览登陆百度官网,会在本地保留一份百度域名的cookie信息;然后你访问登陆360官网,也会保留一份360的cookie信息,然后两个不同域名下的cookie信息可以访问;但是android23之前是支持跨域读取cookie,但是之后就默认不支持了,需要设置

// 设置接收第三方Cookie
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    CookieManager.getInstance().setAcceptThirdPartyCookies(mWebview, true);
}

* 还有Http/Https混合加载的问题,有的网页请求是首页是Https请求,内部一些链接是Http请求,在api23以前是默认允许混合加载的,但是23就开始改了,需要单独设置

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    mSetting.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}

不过可以看看官方的建议再具体根据情况使用

/**
 * Configures the WebView's behavior when a secure origin attempts to load a resource from an
 * insecure origin.
 *
 * By default, apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below default
 * to {@link #MIXED_CONTENT_ALWAYS_ALLOW}. Apps targeting
 * {@link android.os.Build.VERSION_CODES#LOLLIPOP} default to {@link #MIXED_CONTENT_NEVER_ALLOW}.
 *
 * The preferred and most secure mode of operation for the WebView is
 * {@link #MIXED_CONTENT_NEVER_ALLOW} and use of {@link #MIXED_CONTENT_ALWAYS_ALLOW} is
 * strongly discouraged.
 *
 * @param mode The mixed content mode to use. One of {@link #MIXED_CONTENT_NEVER_ALLOW},
 *     {@link #MIXED_CONTENT_ALWAYS_ALLOW} or {@link #MIXED_CONTENT_COMPATIBILITY_MODE}.
 */

* 有的时候可能会碰到打开webivew所在的activity前出现黑屏或者白屏的情况,时间比较短,特别是webivew所在的activity在不同的进程。主要是因为冷启动另一个进程,android创建这个进程的时候需要很多准备动作,有点耗时的,这时候我们就需要进行一些activity主题设置的优化,具体可以参考这篇博客

https://blog.csdn.net/feiduclear_up/article/details/78822775


具体还有多少问题大家可以去这里参加讨论

Android WebView 在开发过程中有哪些坑?



猜你喜欢

转载自blog.csdn.net/qq_30993595/article/details/80678795