当前位置: 首页 > news >正文

鸿蒙网络编程系列27-HTTPS服务端证书的四种校验方式示例

1. 服务端数字证书验证的问题

在鸿蒙客户端对服务端发起HTTPS请求时,如果使用HttpRequest的request发起请求,那么就存在服务端数字证书的验证问题,你只有两个选择,一个是使用系统的CA,一个是使用自己选定的CA,在上文鸿蒙网络编程系列26-HTTPS证书自选CA校验示例中,对此进行了介绍。但是,还有一些更常见的问题难以解决:

  • 可不可以跳过对服务端数字证书的验证

  • 可不可以自定义验证规则,比如,只验证数字证书的公玥,忽略有效期,就是说失效了也可以继续用

如果你还是使用HttpRequest的话,答案是否定的。但是,鸿蒙开发者很贴心的推出了远场通信服务,可以使用rcp模块的方法发起请求,并且在请求时指定服务端证书的验证方式,关键点就在SecurityConfiguration接口上,该接口的remoteValidation属性支持远程服务器证书的四种验证模式:

  • 'system':使用系统CA,默认值

  • 'skip':跳过验证

  • CertificateAuthority:选定CA

  • ValidationCallback:自定义证书校验

Talk is cheap, show you the code!

2. 实现HTTPS服务端证书四种校验方式示例

本示例运行后的界面如下所示:

cke_54800.jpg

选择证书验证模式,在请求地址输入要访问的https网址,然后单击“请求”按钮,就可以在下面的日志区域显示请求结果。

下面详细介绍创建该应用的步骤。

步骤1:创建Empty Ability项目。

步骤2:在module.json5配置文件加上对权限的声明:

"requestPermissions": [{"name": "ohos.permission.INTERNET"}]这里添加了获取互联网信息的权限。

步骤3:在Index.ets文件里添加如下的代码:

import util from '@ohos.util';
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import { BusinessError } from '@kit.BasicServicesKit';
import { rcp } from '@kit.RemoteCommunicationKit';
​
@Entry
@Component
struct Index {//连接、通讯历史记录@State msgHistory: string = ''//请求的HTTPS地址@State httpsUrl: string = "https://47.**.**.***:8081/hello"//服务端证书验证模式,默认系统CA@State certVerifyType: number = 0//是否显示选择CA的组件@State selectCaShow: Visibility = Visibility.None//选择的ca文件@State caFileUri: string = ''scroller: Scroller = new Scroller()
​build() {Row() {Column() {Text("远场通讯HTTPS证书校验示例").fontSize(14).fontWeight(FontWeight.Bold).width('100%').textAlign(TextAlign.Center).padding(10)
​Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("选择服务器HTTPS证书的验证模式:").fontSize(14).width(90).flexGrow(1)}.width('100%').padding(10)
​Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {Column() {Text('系统CA').fontSize(14)Radio({ value: '0', group: 'rgVerify' }).checked(true).height(50).width(50).onChange((isChecked: boolean) => {if (isChecked) {this.certVerifyType = 0}})}
​Column() {Text('指定CA').fontSize(14)Radio({ value: '1', group: 'rgVerify' }).checked(false).height(50).width(50).onChange((isChecked: boolean) => {if (isChecked) {this.certVerifyType = 1}})}
​Column() {Text('跳过验证').fontSize(14)Radio({ value: '2', group: 'rgVerify' }).checked(false).height(50).width(50).onChange((isChecked: boolean) => {if (isChecked) {this.certVerifyType = 2}})}
​Column() {Text('自定义验证').fontSize(14)Radio({ value: '3', group: 'rgVerify' }).checked(false).height(50).width(50).onChange((isChecked: boolean) => {if (isChecked) {this.certVerifyType = 3}})}}.width('100%').padding(10)
​Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("服务端证书CA").fontSize(14).width(90).flexGrow(1)
​Button("选择").onClick(() => {this.selectCA()}).width(70).fontSize(14)}.width('100%').padding(10).visibility(this.certVerifyType == 1 ? Visibility.Visible : Visibility.None)
​Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {Text("请求地址:").fontSize(14).width(80)TextInput({ text: this.httpsUrl }).onChange((value) => {this.httpsUrl = value}).width(110).fontSize(12).flexGrow(1)Button("请求").onClick(() => {this.doHttpRequest()}).width(60).fontSize(14)}.width('100%').padding(10)
​Scroll(this.scroller) {Text(this.msgHistory).textAlign(TextAlign.Start).padding(10).width('100%').backgroundColor(0xeeeeee)}.align(Alignment.Top).backgroundColor(0xeeeeee).height(300).flexGrow(1).scrollable(ScrollDirection.Vertical).scrollBar(BarState.On).scrollBarWidth(20)}.width('100%').justifyContent(FlexAlign.Start).height('100%')}.height('100%')}
​//自定义证书验证方式selfDefServerCertValidation: rcp.ValidationCallback = (context: rcp.ValidationContext) => {//此处编写证书有效性判断逻辑return true;}
​//生成rcp配置信息buildRcpCfg() {let caCert: rcp.CertificateAuthority = {content: this.getCAContent()}//服务器端证书验证模式let certVerify: 'system' | 'skip' | rcp.CertificateAuthority | rcp.ValidationCallback = "system"
​if (this.certVerifyType == 0) { //系统验证certVerify = 'system'} else if (this.certVerifyType == 1) { //选择CA证书验证certVerify =caCert} else if (this.certVerifyType == 2) { //跳过验证certVerify = 'skip'} else if (this.certVerifyType == 3) { //自定义证书验证certVerify = this.selfDefServerCertValidation}let secCfg: rcp.SecurityConfiguration = { remoteValidation: certVerify }let reqCfg: rcp.Configuration = { security: secCfg }let sessionCfg: rcp.SessionConfiguration = { requestConfiguration: reqCfg }return sessionCfg}
​//发起http请求doHttpRequest() {let rcpCfg = this.buildRcpCfg()let rcpSession: rcp.Session = rcp.createSession(rcpCfg)rcpSession.get(this.httpsUrl).then((response) => {if (response.body != undefined) {let result = buf2String(response.body)this.msgHistory += '请求响应信息: ' + result + "\r\n";}}).catch((err: BusinessError) => {this.msgHistory += `err: err code is ${err.code}, err message is ${JSON.stringify(err)}\r\n`;})}
​//选择CA证书文件selectCA() {let documentPicker = new picker.DocumentViewPicker();documentPicker.select().then((result) => {if (result.length > 0) {this.caFileUri = result[0]this.msgHistory += "select file: " + this.caFileUri + "\r\n";}}).catch((e: BusinessError) => {this.msgHistory += 'DocumentViewPicker.select failed ' + e.message + "\r\n";});}
​//加载CA文件内容getCAContent(): string {let caContent = ""try {let buf = new ArrayBuffer(1024 * 4);let file = fs.openSync(this.caFileUri, fs.OpenMode.READ_ONLY);let readLen = fs.readSync(file.fd, buf, { offset: 0 });caContent = buf2String(buf.slice(0, readLen))fs.closeSync(file);} catch (e) {this.msgHistory += 'readText failed ' + e.message + "\r\n";}return caContent}
}
​
​
//ArrayBuffer转utf8字符串
function buf2String(buf: ArrayBuffer) {let msgArray = new Uint8Array(buf);let textDecoder = util.TextDecoder.create("utf-8");return textDecoder.decodeWithStream(msgArray)
}

步骤4:编译运行,可以使用模拟器或者真机。

步骤5:选择默认“系统CA”,输入请求网址(假设web服务端使用的是自签名证书),然后单击“请求”按钮,这时候会出现关于数字证书的错误信息,如图所示:

cke_63643.jpg

步骤6:选择“指定CA”类型,然后单击出现的“选择”按钮,可以在本机选择CA证书文件,然后单击“请求”按钮:

cke_129996.jpg

可以看到,得到了正确的请求结果。

步骤7:选择“跳过验证”类型,然后然后单击“请求”按钮:

cke_159268.jpg

也得到了正确的请求结果。

步骤8:选择“自定义验证”类型,然后然后单击“请求”按钮:

cke_253658.jpg

也得到了正确的请求结果。

3. 关键功能分析

关键点主要有两块,第一块是设置验证模式:

    //服务器端证书验证模式let certVerify: 'system' | 'skip' | rcp.CertificateAuthority | rcp.ValidationCallback = "system"
​if (this.certVerifyType == 0) { //系统验证certVerify = 'system'} else if (this.certVerifyType == 1) { //选择CA证书验证certVerify =caCert} else if (this.certVerifyType == 2) { //跳过验证certVerify = 'skip'} else if (this.certVerifyType == 3) { //自定义证书验证certVerify = this.selfDefServerCertValidation}let secCfg: rcp.SecurityConfiguration = { remoteValidation: certVerify }let reqCfg: rcp.Configuration = { security: secCfg }let sessionCfg: rcp.SessionConfiguration = { requestConfiguration: reqCfg }return sessionCfg}

这个比较好理解,第二块是自定义证书验证的方法:

  //自定义证书验证方式selfDefServerCertValidation: rcp.ValidationCallback = (context: rcp.ValidationContext) => {//此处编写证书有效性判断逻辑return true;}

这里为简单起见,自定义规则是所有的验证都通过,读者可以根据自己的需要来修改,比如不验证证书的有效期。

(本文作者原创,除非明确授权禁止转载)

本文源码地址:

https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/rcp/RCPCertVerify

本系列源码地址:

https://gitee.com/zl3624/harmonyos_network_samples

相关文章:

鸿蒙网络编程系列27-HTTPS服务端证书的四种校验方式示例

1. 服务端数字证书验证的问题 在鸿蒙客户端对服务端发起HTTPS请求时,如果使用HttpRequest的request发起请求,那么就存在服务端数字证书的验证问题,你只有两个选择,一个是使用系统的CA,一个是使用自己选定的CA&#xf…...

scala继承

Scala中继承的定义为在原有类的基础上定义一个新类,原有类称为父类,新类称为子类。 当子类从父类中继承的方法不能满足需要时,子类需要有自己的行为,怎么办? 此时使用override可以重写父类方法。 class Aniaml(){va…...

【Hive】2-Apache Hive概述、架构、组件、数据模型

Apache Hive概述 什么是Hive Apache Hive是一款建立在Hladoop之上的开源数据仓库系统,可以将存储在Hadoop文件中的结构化、半结构化数据文件映射为一张数据库表,基于表提供了一种类似SQL的查询模型,称为Hive查询语言(HQL),用于访…...

关于目前面试八股文的一些心得体会

现在是2024年10月,自22年开始,明显感觉到整个计算机行业,越来越卷了。一方面,随着信息的传播,越来越多的新人涌入了这个赛道,另一方面,众所周知的原因,不管大厂还是小厂在经历寒冬之…...

大数据-178 Elasticsearch Query - Java API 索引操作 文档操作

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…...

PHP(一)从入门到放弃

参考文献:https://www.php.net/manual/zh/introduction.php PHP 是什么? PHP(“PHP: Hypertext Preprocessor”,超文本预处理器的字母缩写)是一种被广泛应用的开放源代码的多用途脚本语言,它可嵌入到 HTML…...

基于深度学习的生物启发的学习系统

基于深度学习的生物启发学习系统(Biologically Inspired Learning Systems)旨在借鉴生物大脑的结构和学习机制,设计出更高效、更灵活的人工智能系统。这类系统融合了生物神经科学的研究成果,通过模仿大脑中的学习模式、记忆过程和…...

10_实现readonly

在某些时候,我们希望定义一些数据是只读的,不允许被修改,从而实现对数据的保护,即为 readonly 只读本质上也是对数据对象的代理,我们同样可以基于之前实现的 createReactiveObject 函数来实现,可以为此函数…...

简单介绍$listeners

$listeners 它可以获取父组件传递过来的所有自定义函数&#xff0c;如下&#xff1a; // 父组件 <template><div class"a"><Child abab"handleAbab" acac"handleAcac"/></div> </template><script> impor…...

架构设计笔记-20-补充知识

知识产权 我国没有专门针对知识产权制定统一的法律(知识产权法)&#xff0c;而是在民法通则规定的原则下&#xff0c;根据知识产权的不同类型制定了不同的单项法律及法规&#xff0c;如著作权法、商标法、专利法、计算机软件保护条例等&#xff0c;这些法律、法规共同构成了我…...

scrapy 爬虫学习之【中医药材】爬虫

本项目纯学习使用。 1 scrapy 代码 爬取逻辑非常简单&#xff0c;根据url来处理翻页&#xff0c;然后获取到详情页面的链接&#xff0c;再去爬取详情页面的内容即可&#xff0c;最终数据落地到excel中。 经测试&#xff0c;总计获取 11299条中医药材数据。 import pandas as…...

PDH稳频技术粗谈

PDH&#xff08;Plesiochronous Digital Hierarchy&#xff09;是一种传输技术&#xff0c;主要用于数字通信中的传输系统。PDH稳频技术是指在PDH传输系统中&#xff0c;通过稳定频率来实现传输系统的稳定性和可靠性。 PDH传输系统中&#xff0c;时钟同步是非常重要的。传输系…...

[LeetCode] 130. 被围绕的区域

题目描述&#xff1a; 给你一个 m x n 的矩阵 board &#xff0c;由若干字符 X 和 O 组成&#xff0c;捕获 所有 被围绕的区域&#xff1a; 连接&#xff1a;一个单元格与水平或垂直方向上相邻的单元格连接。区域&#xff1a;连接所有 O 的单元格来形成一个区域。围绕&#x…...

C语言位运算

目录 1.C语言位运算符表 2.C语言移位运算符详解&#xff08;配实例作业&#xff09; 3.C语言&按位与运算符详解 4.C语言|按位或运算符详解 5.C语言^按位异或运算符详解 6.C语言~取反运算符详解 C语言位运算这一章主要介绍C语言位运算符表、C语言移位运算符、C语言&按…...

Go 语言中格式化动词

当然&#xff0c;我很乐意为你提供 Go 语言中所有的格式化动词的完整列表。Go 语言的格式化动词非常丰富&#xff0c;可以满足各种打印和格式化需求。以下是完整的列表&#xff1a; 通用&#xff1a; %v - 以默认格式打印值 %v - 类似 %v&#xff0c;但对结构体会添加字段名 %#…...

CSS3 动画相关属性实例大全(四)(font、height、left、letter-spacing、line-height 属性)

CSS3 动画相关属性实例大全&#xff08;四) &#xff08;font、height、left、letter-spacing、line-height 属性&#xff09; 本文目录&#xff1a; 一、font 属性&#xff08;所有字体属性&#xff09; 1.1、font-size属性&#xff08;指定字体的大小&#xff09; 1.2、f…...

大模型涌现判定

什么是大模型&#xff1f; 大模型&#xff1a;是“规模足够大&#xff0c;训练足够充分&#xff0c;出现了涌现”的深度学习系统&#xff1b; 大模型技术的革命性&#xff1a;延申了人的器官的功能&#xff0c;带来了生产效率量级提升&#xff0c;展现了AGI的可行路径&#x…...

LeetCode 1456.定长子串中元音的最大数目

题目&#xff1a; 给你字符串 s 和整数 k 。 请返回字符串 s 中长度为 k 的单个子字符串中可能包含的最大元音字母数。 英文中的 元音字母 为&#xff08;a, e, i, o, u&#xff09;。 思路&#xff1a;定长滑动窗口 入 更新 出 代码&#xff1a; class Solution {pub…...

freeswitch-esl 三方设备实现监听功能

使用场景: A和B在通话中,C想监听A和B通话内容 方法一: 修改拨号计划<extension name="global" continue="true"><condition><action application="info"/>...

【LeetCode】123.买卖股票的最佳时间

清晰明了的思路是解决问题的至上法宝。如何把一个复杂的问题拆成简单的问题&#xff0c;就是我们需要考虑的。 1. 题目 2. 思想 这道题虽然是难题&#xff0c;但是思想比较简单。 题目要求说至多买卖两次&#xff0c;也就是说&#xff0c;也可以买卖一次&#xff0c;这种情况…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

离线语音识别方案分析

随着人工智能技术的不断发展&#xff0c;语音识别技术也得到了广泛的应用&#xff0c;从智能家居到车载系统&#xff0c;语音识别正在改变我们与设备的交互方式。尤其是离线语音识别&#xff0c;由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力&#xff0c;广…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...