当前位置: 首页 > 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;这种情况…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

从零开始了解数据采集(二十八)——制造业数字孪生

近年来&#xff0c;我国的工业领域正经历一场前所未有的数字化变革&#xff0c;从“双碳目标”到工业互联网平台的推广&#xff0c;国家政策和市场需求共同推动了制造业的升级。在这场变革中&#xff0c;数字孪生技术成为备受关注的关键工具&#xff0c;它不仅让企业“看见”设…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解

文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...

React、Git、计网、发展趋势等内容——前端面试宝典(字节、小红书和美团)

React React Hook实现架构、.Hook不能在循环嵌套语句中使用 , 为什么&#xff0c;Fiber架构&#xff0c;面试向面试官介绍&#xff0c;详细解释 用户: React Hook实现架构、.Hook不能在循环嵌套语句中使用 , 为什么&#xff0c;Fiber架构&#xff0c;面试向面试官介绍&#x…...