Android WebView https白屏、Http和Https混合问题、证书配置和使用

目录

  • 前言
  • 启用https后白屏(证书错误)
  • 修改处理
  • WebView中Http和Https混合问题
    • 处理办法
    • Webview的几种内容加载模式
  • 证书配置或处理
  • https请求的证书
    • okhttp进行请求:
    • HttpsURLConnection
    • 忽略证书

前言

原有项目中有部分界面是用webview展现的h5页面,一直以来都使用的http地址,但有些情况下,用户dns被劫持,页面上出现了一些广告的内容,或者页面就是白屏,总结起来还是因为使用http,页面内容被劫持修改,修改后的内容要么多出广告,要么被修改得加载不出来,因此项目中自然就需要加载https的地址。同时修改为https之后,出现问题的那些用户也能正常的显示出h5页面内容。

启用https后白屏(证书错误)

然而,在新版本上线后,有客户反馈oppo(8.1)、vivo等用户反馈app中页面白屏,单位的oppo和vivo验证都没有问题。最后小伙伴用模拟器复现了,同时也看到错误日志:
在这里插入图片描述
此处的日志是在WebChromeClient的重实现打出来的(代码已经修改过):

  @Overridepublic void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {GenseeLog.e(TAG,"onReceivedSslError sslErrorHandler = [" + sslErrorHandler + "], sslError = [" + sslError + "]");_onReceivedError();super.onReceivedSslError(webView, sslErrorHandler, sslError);}

修改处理

得知是在WebChromeClient的onReceivedSslError重实现中响应了相关的错误,在onReceivedSslError中调用sslErrorHandler.process(); 就可以了:忽略证书问题。

     public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {GenseeLog.e(TAG,"onReceivedSslError sslErrorHandler = [" + sslErrorHandler + "], sslError = [" + sslError.getPrimaryError() + "]");_onReceivedError();sslErrorHandler.proceed();
//                super.onReceivedSslError(webView, sslErrorHandler, sslError);}

此处注意:不要调用super.onReceivedSslError(webView, sslErrorHandler, sslError),super的实现是sslErrorHandler.cancel();,终止访问。

   public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {handler.cancel();}

注意:文本是通过忽略证书的问题处理的,但从实质性的安全来说并没起到作用。确认我们的证书是无误的。唯独几个oppo(系统8.1)和vivo用户有问题,目前没有得到真机的验证,推测还是系统证书下载问题。有知道的老铁请留言,感谢之。
正确建议做法是做证书校验:

webView.setWebViewClient(new  WebViewClient() {overridepublic void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {String msg;switch(error.getPrimaryError()) {case: SslError.SSL_DATE_INVALIDmsg = "证书日期无效"break;case: SslError.SSL_EXPIREDmsg =  "证书已过期。"break;case: SslError.SSL_IDMISMATCH msg = "主机名不匹配。"break;case: SslError.SSL_INVALID msg = "发生一般错误"break;case: SslError.SSL_MAX_ERRORmsg = "不同SSL错误的数量。"break;case: SslError.SSL_NOTYETVALIDmsg =  "证书尚未生效。"break;case: SslError.SSL_UNTRUSTEDmsg =  "证书颁发机构不受信任。" // 自定义证书会执行到这个分支来break;default:msg ="SSL证书错误,错误码:"+ error.getPrimaryError();}Log.i("SSL错误:" + msg)if (error.getPrimaryError() == SslError.SSL_UNTRUSTED) {// 证书颁发机构不受信任,则我们需要判断一下是否是我们自己的自定义证书,是的话就忽略这个错误CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");X509Certificate certificate = certificateFactory.generateCertificate(resources.openRawResource(R.raw.xxx)) ;Field mX509CertificateFiled = SslCertificate.getClass().getDeclaredField("mX509Certificate");mX509CertificateFiled .setAccessible( true);X509Certificate mX509Certificate = mX509CertificateFiled.get(error.certificate());val certificates = HandshakeCertificates.Builder().addTrustedCertificate(certificate) // 信任指定的自定义证书.addPlatformTrustedCertificates()  // 信任系统的预装证书,如果不信任系统证书的话,比如在访问https://m.baidu.com时将会出错.build()try {certificates.trustManager.checkServerTrusted(new X509Certificate []{mX509Certificate}), "RSA")Log.i("是我们的自定义证书")handler.proceed()} catch (e: java.lang.Exception) {Log.e(e, "非法证书")handle.cancel()}}} else {super.onReceivedSslError(view, handler, error)}}
});

WebView中Http和Https混合问题

在一个页面通过http请求的,但页面内有https的资源,后者页面是通过https访问的,但页面内有http的资源,这样的混合,一般后者都存在问题,当前前者也可能存在问题。

处理办法

在webview加载页面之前,设置加载模式为MIXED_CONTENT_ALWAYS_ALLOW

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

在Android5.0之前,系统默认是采用的MIXED_CONTENT_ALWAYS_ALLOW模式,即总是允许WebView同时加载Https和Http;而从Android5.0开始,默认用MIXED_CONTENT_NEVER_ALLOW模式,即总是不允许WebView同时加载Https和Http。

如果都是自家的网页,那这个问题还是从源头上进行处理,页面不要使用混合的方式。

官网给出的建议是,为了安全考虑,使用 MIXED_CONTENT_NEVER_ALLOW模式,但是在实际引用中,当我们的服务器已经升级到Https,但是一些页面的资源是第三方的,我们不一定能要求第三方也都升级到Https,所以我们只能根据系统版本,用代码去设置加载模式为MIXED_CONTENT_ALWAYS_ALLOW。

Webview的几种内容加载模式

从Android5.0开始,当一个安全的站点(https)去加载一个非安全的站点(http)时,需要配置Webview加载内容的混合模式,一共有如下三种模式:

  • MIXED_CONTENT_NEVER_ALLOW:Webview不允许一个安全的站点(https)去加载非安全的站点内容(http),比如,https网页内容的图片是http链接。强烈建议App使用这种模式,因为这样更安全。
  • MIXED_CONTENT_ALWAYS_ALLOW:在这种模式下,WebView是可以在一个安全的站点(Https)里加载非安全的站点内容(Http),这是WebView最不安全的操作模式,尽可能地不要使用这种模式。
  • MIXED_CONTENT_COMPATIBILITY_MODE:在这种模式下,当涉及到混合式内容时,WebView会尝试去兼容最新Web浏览器的风格。一些不安全的内容(Http)能被加载到一个安全的站点上(Https),而其他类型的内容将会被阻塞。这些内容的类型是被允许加载还是被阻塞可能会随着版本的不同而改变,并没有明确的定义。这种模式主要用于在App里面不能控制内容的渲染,但是又希望在一个安全的环境下运行。

证书配置或处理

如果需要配置证书的情况下,
在res目录下创建一个xml文件目录,再创建一个network_security_config.xml(名字可随意),然后就是在这个文件中写入一些关于https的配置,接着把network_security_config配置到Anroidmanifest的Application节点属性中,如下:

<applicationandroid:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:networkSecurityConfig="@xml/network_security_config"></application>

我们的xxx.crt的证书文件按照规范,需要放到res/raw/目录下面。接着配置到network_security_config文件中。配置证书,有两种方式,如下:

  1. base-config
    表示应用的访问的所有域名的资源都信任我们指定的xxx证书
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config><trust-anchors><certificates src="@raw/xxx" /></trust-anchors></base-config>
</network-security-config>
  1. domain-config
    使用domain-config限制了gensee.com或它的子域名都信任我们指定的xxx证书
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><domain-config><domain includeSubdomains="true">gensee.com</domain><trust-anchors><certificates src="@raw/xxx"/></trust-anchors></domain-config>
</network-security-config>
  1. 指定信任预安装的证书
    配置我们要信任什么证书,直接使用@raw/xxx为配置信任自定义的证书,如果要指定信任预安装的证书,需要另外指定,预安装的证书有系统和用户两种类型,如下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config><base-config><trust-anchors><certificates src="@raw/custom_ca" /> <!--信任自定义的CA证书--><certificates src="system" /> <!--信任系统预装的CA证书--><certificates src="user" />   <!--信任用户安装的CA证书--></trust-anchors></base-config>
</network-security-config>

https请求的证书

okhttp进行请求:

val builder = OkHttpClient.Builder()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {val certificateFactory: CertificateFactory = CertificateFactory.getInstance("X.509")val certificate = certificateFactory.generateCertificate(resources.openRawResource(R.raw.xxx)) as X509Certificateval certificates = HandshakeCertificates.Builder().addTrustedCertificate(certificate) // 信任指定的自定义证书.addPlatformTrustedCertificates()  // 信任系统的预装证书,如果不信任系统证书的话,比如在访问https://m.baidu.com时将会出错.build()builder.sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager)
}
val okHttpClient = builder.build()

HttpsURLConnection

    // Load CAs from an InputStream// (could be from a resource or ByteArrayInputStream or ...)val cf: CertificateFactory = CertificateFactory.getInstance("X.509")// From https://www.washington.edu/itconnect/security/ca/load-der.crtval caInput: InputStream = BufferedInputStream(FileInputStream("load-der.crt"))val ca: X509Certificate = caInput.use {cf.generateCertificate(it) as X509Certificate}System.out.println("ca=" + ca.subjectDN)// Create a KeyStore containing our trusted CAsval keyStoreType = KeyStore.getDefaultType()val keyStore = KeyStore.getInstance(keyStoreType).apply {load(null, null)setCertificateEntry("ca", ca)}// Create a TrustManager that trusts the CAs inputStream our KeyStoreval tmfAlgorithm: String = TrustManagerFactory.getDefaultAlgorithm()val tmf: TrustManagerFactory = TrustManagerFactory.getInstance(tmfAlgorithm).apply {init(keyStore)}// Create an SSLContext that uses our TrustManagerval context: SSLContext = SSLContext.getInstance("TLS").apply {init(null, tmf.trustManagers, null)}// Tell the URLConnection to use a SocketFactory from our SSLContextval url = URL("https://certs.cac.washington.edu/CAtest/")val urlConnection = url.openConnection() as HttpsURLConnectionurlConnection.sslSocketFactory = context.socketFactoryval inputStream: InputStream = urlConnection.inputStreamcopyInputStreamToOutputStream(inputStream, System.out)

忽略证书

/** 获取一个SSLSocketFactory */
val sSLSocketFactory: SSLSocketFactoryget() = try {val sslContext = SSLContext.getInstance("SSL")sslContext.init(null, arrayOf(trustManager), SecureRandom())sslContext.socketFactory} catch (e: Exception) {throw RuntimeException(e)}/** 获取一个忽略证书的X509TrustManager */
val trustManager: X509TrustManagerget() = object : X509TrustManager {override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) { }	override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) { }	override fun getAcceptedIssuers(): Array<X509Certificate> { return arrayOf() }}

将这两个对象设置给okhttp或HttpsURLConnection即可完成证书忽略。

https://blog.csdn.net/android_cai_niao/article/details/108065766
https://blog.csdn.net/luofen521/article/details/51783914

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kotlin AAPT: error: resource android:attr/lStar not found.

这是使用kotlin之后发生的错误。 打开 android/app 工程全局搜索androidx.core:core-ktx: 全局搜索快捷键 ctrlshift f将搜索到的内容修改为androidx.core:core-ktx:1.6.0 也就是说将androidx.core:core-ktx: 修改为androidx.core:core-ktx:1.6.0,一般情况下是在module的中的b…

python selenium iframe怎么定位_python+selenium四:iframe查看、定位、切换

iframe是HTML里面嵌套HTML的一种框架1.查看iframe1.Top Window&#xff1a;可直接定位2.iframe#i&#xff1a;说明此元素在iframe上3.iframe显示为空&#xff1a;(id或name为空)4.右边这个看到是空的(2层iframe)以126邮箱为例from selenium import webdriverdriver webdriver.…

Kotlin plugin should be enabled before ‘kotlin-android-extensions‘

问题一 、Kotlin plugin should be enabled before ‘kotlin-android-extensions‘ 在java项目中添加kotlin的类之后&#xff0c;根据提示进行各种配置和下载&#xff0c;一顿操作后出现了Kotlin plugin should be enabled before kotlin-android-extensions’ 处理办法&…

python增加工作日列_将工作日添加到日期字段

我试图在Django的日期字段中添加一些工作日。这是针对产品订购&#xff0c;我们对不同的产品有不同的交付周期&#xff0c;我们希望为每个产品生成一个目标日期。在例如&#xff0c;产品X可能需要10个工作日才能交付&#xff0c;如果此产品是在2013年3月1日星期五订购的&#x…

tensorrt轻松部署高性能dnn推理_基于TensorRT车辆实时推理优化

基于TensorRT车辆实时推理优化Optimizing NVIDIA TensorRT Conversion for Real-time Inference on Autonomous Vehicles自动驾驶系统使用各种神经网络模型&#xff0c;这些模型要求在GPU上进行极其精确和高效的计算。Zoox是一家全新开发robotaxis的初创公司&#xff0c;充分利…

问卷调查试卷的数据设计

目录前言数据定义数据说明1、第一层{}2、question 一个题目{}3、answer一个答题回复{}4、option 一个选项{}5、selectItems {}具体数据1、发题&#xff08;终端请求&#xff09;示例2、答题(图片答题&#xff0c;终端请求)互动或静态3、停止答题(终端请求&#xff0c;一般是互动…

手机上网流量统计_数据统计 | 上半年手机流量同比增110.2%,你贡献了多少?

来源&#xff1a;工信部网站、中新经纬版权申明&#xff1a;内容来源网络&#xff0c;版权归原创者所有。除非无法确认&#xff0c;我们都会标明作者及出处&#xff0c;如有侵权烦请告知我们&#xff0c;我们会立即删除并表示歉意。谢谢&#xff01;7月25日&#xff0c;工信部网…

Kotlin静态方法定义和调用

在习惯java的开发之后&#xff0c;使用kotlin进行编码&#xff0c;总有那么些不自然。 静态类的定义&#xff1a; 全局静态(实际上是单例模型) 直接将类声明为object&#xff0c;那么所有的函数也就静态的了&#xff0c;这种一般适用于各种util的类。 object UIUtil {fun to…

mybatis insert插入成功返回0_mybatis添加客户

在MyBatis的映射文件中&#xff0c;添加操作是通过元素来实现的。例如&#xff0c;向数据库中的t_customer表中插入一条数据可以通过如下配置来实现。在上述配置代码中&#xff0c;传入的参数是一个Customer类型&#xff0c;该类型的参数对象被传递到语句中时&#xff0c;#{use…

Andoid TextView显示富文本html内容及问题处理

目录富文本内容与效果TextView HtmlImageGetter 处理图片(表情)TagHandler 处理html内容的节点Html的转换过程HtmlToSpannedConverterhandleStartTagstartCssStyle(mSpannableStringBuilder, attributes)字体无效果实现getForegroundColorPattern颜色不显示的坑处理办法颜色修…

mysql截取字符串最后两位_MySQL字符串函数substring:字符串截取

MySQL 字符串截取函数&#xff1a;left(), right(), substring(), substring_index()。还有 mid(), substr()。其中&#xff0c;mid(), substr() 等价于 substring() 函数&#xff0c;substring() 的功能非常强大和灵活。1. 字符串截取&#xff1a;left(str, length)mysql> …

Java类加载顺序之一条日志引发的血案

目录为什么是null回顾类加载原因问题重现总结类加载顺序子类重写被父类构造函数调用的函数注意不能放过不起眼的日志一条日志引发的案子 [11:12:58.505][D][Gen][RTLive][getIns ins 4414717] [11:12:58.774][I][Gen][null][updateShowMode] [11:12:58.864][D][Gen][VideoCame…

Java错误:找不到或无法加载主类

目录前言javac xxx.java 编译需要相对物理路径java xxx 执行需要虚拟路径总结前言 一般情况下&#xff0c;我们都使用工具进行代码的编辑和调试&#xff0c;例如eclipse 、Manven、Android Studio、sublime、vim、notepad、记事本等。 当我们用eclipse android studio等创建的p…

vue取通过key取value_如何通过获取map中的key来获得与key对应的value值,进行运算...

展开全部获取map的key和value的方法分为以下62616964757a686964616fe4b893e5b19e31333366306439两种形式&#xff1a;1、map.keySet()&#xff1a;先获取map的key&#xff0c;然后根据key获取对应的value&#xff1b;2、map.entrySet()&#xff1a;同时查询map的key和value&…

Android坑点-ByteBuffer.array() 入过坑吗

目录1、坑点介绍2、正确使用姿势&#xff08;入坑了怎么办&#xff09;3、坑坑详解3.1HeapByteBuffer可以用buffer.array()3.2DirectByteBuffer的坑在哪里1、坑点介绍 如下代码&#xff1a; ByteBuffer buffer ByteBuffer.allocateDirect(int capacity) byte[] array buf…

php四则运算出题器_php实现简单四则运算器

本文实例为大家分享了php实现简单四则运算器的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下前端代码 &#xff1a;php计算器请输入num1&#xff1a;请选择运算符&#xff1a;-*/%请输入num2&#xff1a;后台&#xff1a;php计算器$num1$_post["num1"];$n…

步苹果iOS的后尘,谷歌Android12“翻车”,更新需谨慎?

苹果不论电脑还是移动设备&#xff0c;都是一如既往的“强硬”。说实话&#xff0c;忽视“兼容”&#xff0c;体验极低。 有小伙伴调侃&#xff1a;人家就是要你买新机器。也有小伙伴&#xff08;包括我在内&#xff09;&#xff0c;直接关闭系统自动更新。 开发者&#xff1a…

word把选择答案弄到题目里_word中把选择题的正确答案自动填到括号里技巧

为了适应各类复习迎考&#xff0c;大家都会利用一些题目来练习。当面对题目与答案分离的现状(两个文档或一个文档的两个部分)时&#xff0c;怎样将题目和答案合二为一&#xff0c;使答案自动填充到题目后的括号中是颇让大家头疼的一件事情。经过实践探索多步骤的组合操作可以实…

Android Studio无线连接设备调试,比数据线更方便

前言 一般情况下&#xff0c;多数移动开发者使用的是数据线连接电脑&#xff0c;进行各种移动设备的调试&#xff0c;更有胜者&#xff0c;非常迷恋模拟器&#xff0c;模拟器它好不好&#xff0c;答案是好&#xff0c;因为直接运行在电脑上&#xff0c;直接操作&#xff0c;调试…

机器学习里面的基函数_神经网络与机器学习 笔记—核方法和径向基函数网络(上)...

对于神经网络的监督学习有多种不同方法。之前一直总结整理的多层感知器反向传播算法&#xff0c;可以看做是递归技术的应用&#xff0c;这种技术在统计学中通称为随机逼近。这次是采用不同的途径&#xff0c;通过包含如下两个阶段的混合方式解决非线性可分模式的分类问题&#…