Flutter 自签名证书
前言
Flutter项目中服务器使用了自签名证书,如果直接使用https请求或者wss请求的话会报证书签名错误。
HandshakeException: Handshake error in client (OS Error:
I/flutter (28959): │ 💡 CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359))
或者
CERTIFICATE_VERIFY_FAILED: self signed certificate in certificate chain(handshake.cc:354))
信任自签名证书
1.忽略证书校验
你可以通过以下步骤忽略证书验证。从而接受自签名证书
首先创建一个class 重写HttpOverrides
class MyHttpOverrides extends HttpOverrides {HttpClient createHttpClient(SecurityContext context) {return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) {//add your certificate verification logic herereturn true;};}
}
然后在main 方法将MyHttpOverrides 设置成全局的HttpOverrides。
HttpOverrides.global = new DevHttpOverrides();
当系统检测证书有问题时,会通过回调badCertificateCallback让我们有机会接受或拒绝这个错误的证书,当返回true时,表示我们接受这个证书,会继续完成通讯请求,当返回false时,表示我们不接受错误的证书,https通讯将失败。
当然你也可以在badCertificateCallback添加自己的证书校验逻辑。强烈不建议在正式环境将badCertificateCallback直接返回true,因为这样会接受所有的证书,相当于SSL加密层形同虚设,很容易造成中间人攻击。
2.使用本地CA根证书验证服务器证书
我们可以将服务器用来生成自签名证书的CA证书放在本地,设置为受信任的证书,然后用这个证书校验服务器证书。代码如下:
class MyHttpOverrides extends HttpOverrides {HttpClient createHttpClient(SecurityContext context) {//加载本地根证书ByteData data = await rootBundle.load('assets/data/ca-cert.pem');final SecurityContext clientContext = SecurityContext()//使用此方法设置受信任根证书..setTrustedCertificatesBytes(data.buffer.asUint8List())return super.createHttpClient(context)..badCertificateCallback = (X509Certificate cert, String host, int port) {//add your certificate verification logic herereturn false;};}
}
这种方式能极大提高安全性。
常见问题
CERTIFICATE_VERIFY_FAILED: Hostname mismatch
Flutter ssl默认会检测证书 subject 中的CN字段和请求url 中的host 是否一致。 如果不一致会报这个错误。
如果请求的url时https://baidu.com/tanslate , 那么服务器的证书CN字段必须包含Baidu.com。
很可惜目前基于flutter3.0 没有提供相应的API 去忽略hostname 检测,我们能做的就是在badCertificateCallback 添加自己的校验逻辑,如下:
..badCertificateCallback = (X509Certificate cert, String host, int port) {if(host=="baidu.com")return true;else return false;};
2.本地CA根证书验证服务器证书时,当服务器证书的签名不对时,会回调到badCertificateCallback, 而其他证书错误也会回调到badCertificateCallback, 如果要如何区分不同的证书错误原因,则需要手动去校验证书的签名等信息。
class MyHttpOverrides extends HttpOverrides {MyHttpOverrides() {}HttpClient createHttpClient(SecurityContext? context) {ByteData data = await rootBundle.load('assets/data/ca-cert.pem');final SecurityContext clientContext = SecurityContext()..setTrustedCertificatesBytes(caCertificate);return super.createHttpClient(clientContext)..badCertificateCallback = (X509Certificate cert, String host, int port) //根据根证书校验服务器证书bool isverify = verifyCertificate(ca_cert, cert.pem);if (!isverify){//签名错误return false;}if (currentIp != host) {return false;} else {return true;}};}
}
其中verifyCertificate 方法如下,用到了x509这个package。传送门
import 'dart:convert';
import 'dart:typed_data';
import 'package:x509b/x509.dart' as x509;
import 'package:asn1lib/asn1lib.dart';import 'flutter_log.dart';bool verifyCertificate(String caCert, String serverCert) {// var strX1PublicKeyInfo = "-----BEGIN CERTIFICATE-----\nSOME PUBLIC KEY\n-----END CERTIFICATE-----";// var strX2Certificate = "-----BEGIN CERTIFICATE-----\nSOME CERTIFICATE\n-----END CERTIFICATE-----";var x1PublicKey = (x509.parsePem(caCert).single as x509.X509Certificate).publicKey as x509.RsaPublicKey;var x2Certificate = x509.parsePem(serverCert).single as x509.X509Certificate;var x2CertificateDER = decodePEM(serverCert);var asn1Parser = ASN1Parser(x2CertificateDER);var seq = asn1Parser.nextObject() as ASN1Sequence;var tbsSequence = seq.elements[0] as ASN1Sequence;var signature = x509.Signature(Uint8List.fromList(x2Certificate.signatureValue!));var verifier = x1PublicKey.createVerifier(x509.algorithms.signing.rsa.sha256);return verifier.verify(tbsSequence.encodedBytes, signature);
}Uint8List decodePEM(String pem) {var startsWith = ['-----BEGIN PUBLIC KEY-----','-----BEGIN PRIVATE KEY-----','-----BEGIN CERTIFICATE-----',];var endsWith = ['-----END PUBLIC KEY-----','-----END PRIVATE KEY-----','-----END CERTIFICATE-----'];pem=pem.trim();//HACKfor (var s in startsWith) {if (pem.startsWith(s)) pem = pem.substring(s.length);}for (var s in endsWith) {if (pem.trim().endsWith(s)) {Log().i("certificate:substring");pem = pem.trim().split(s)[0];}}//Dart base64 decoder does not support line breakspem = pem.replaceAll('\n', '');pem = pem.replaceAll('\r', '');return Uint8List.fromList(base64.decode(pem));
}
作者:星辰大海TT
链接:https://www.jianshu.com/p/5dfb882671a3
相关文章:
Flutter 自签名证书
前言 Flutter项目中服务器使用了自签名证书,如果直接使用https请求或者wss请求的话会报证书签名错误。 HandshakeException: Handshake error in client (OS Error: I/flutter (28959): │ 💡 CERTIFICATE_VERIFY_FAILED: unable to get local issuer c…...

观察者模式——解决解耦的钥匙
● 观察者模式介绍 观察者模式是一个使用频率非常高的模式,它最常用的地方是GUI系统、订阅——发布系统。因为这个模式的一个重要作用就是解耦,将被观察者和观察者解耦,使得它们之间依赖性更小,甚至做到毫无依赖。以CUI系统来说&a…...
MATLAB和西门子SMART PLC UDP通信
MATLAB和SMART PLC的OPC通信请参考下面文章链接,这里不再赘述: MATLAB和西门子SMART PLC OPC通信-CSDN博客文章浏览阅读661次,点赞26次,收藏2次。西门子S7-200SMART PLC OPC软件的下载和使用,请查看下面文章Smart 200PLC PC Access SMART OPC通信_基于pc access smart的o…...

打造高效运营底座,极智嘉一体化软件系统彰显科技威能
在仓储成本和物流需求日益增加的今天,创新且高效的物流机器人解决方案能够显著提升物流运营效率,降低物流成本,实现智能化、精益化、一体化的物流管理。全球仓储机器人引领者极智嘉(Geek)以「一套系统,天生全能」为准则࿰…...

sqlsugar查询数据库下的所有表,批量修改表名字
查询数据库中的所有表 using SqlSugar;namespace 批量修改数据库表名 {internal class Program{static void Main(string[] args){SqlSugarClient sqlSugarClient new SqlSugarClient(new ConnectionConfig(){ConnectionString "Data Source(localdb)\\MSSQLLocalDB;In…...

如何用 GPT-4 全模式(All Tools)帮你高效学习和工作?
「十项全能」的 ChatGPT ,用起来感受如何? 之前,作为 ChatGPT Plus 用户,如果你集齐下面这五个模式,就会成为别人羡慕的对象。 但现在,人们更加期盼的,是下面这个提示的出现: 这个提…...

Cesium 展示——移动拖拽实体
文章目录 需求分析需求 将移动实体的事件加入右键中 ,实现移动拖拽实体,实现对实体的拖拽 移动前 移动后 分析 当鼠标按下时获取该实体。用viewer.scene.pick 来进行获取实体,并锁定相机(需加判断如果不是实体不能锁定相机)// 左键按下事件leftDownAction(e)...

javaSE学习笔记-未完
目录 前言 一、java基础 1.1概述 1.java语言发展史 2.Java语言版本 3.Java语言平台 4.Java语言特点 5.Java语言跨平台原理-可移植性 6.JRE和JDK的概述 7.JDK的下载和安装 8.JDK安装路径下的目录解释 9.path环境变量的作用及配置方式 10.classpath环境变量的作用及…...

分享一下微信小程序里怎么创建会员卡功能
在当今的数字化时代,微信小程序已经成为一种广泛使用的应用模式,涵盖了各种行业。对于企业而言,拥有一个会员卡系统可以更好地管理客户,提高客户忠诚度,并促进消费。本文将探讨如何在微信小程序中创建会员卡功能&#…...

吴恩达《机器学习》5-6:向量化
在深度学习和数值计算中,效率和性能是至关重要的。一个有效的方法是使用向量化技术,它可以显著提高计算速度,减少代码的复杂性。接下来将介绍向量化的概念以及如何在不同编程语言和工具中应用它,包括 Octave、MATLAB、Python、Num…...

《面向对象软件工程》笔记——1-2章
“学习不仅是一种必要,而且是一种愉快的活动。” - 尼尔阿姆斯特朗 文章目录 第一章 面向对象软件工程的范畴历史方面经济方面维护方面现代软件维护观点交付后维护的重要性 需求、分析和设计方面团队开发方面没有计划,测试,文档阶段的原因面向…...

1400台光刻机,ASML突然大举倾销,外媒惊呼中国芯片进展太快了
就在各方还认为中国芯片在高端芯片方面难以突破的时候,ASML却突然公布了重大消息,累计向中国交付的光刻机已达到1400台,中国已成为ASML的最大市场,这样的消息无疑让外媒颇为震惊。 发生这些变化,在于中国芯片近期所取得…...

Leetcode—187.重复的DNA序列【中等】
2023每日刷题(二十) Leetcode—187.重复的DNA序列 实现代码 class Solution { public:const int L 10;vector<string> findRepeatedDnaSequences(string s) {unordered_map<string, int> str;vector<string> ans;int len s.size()…...

inno setup 运行时进行文件复制和替换
问题描述: 当我们采用 inno setup进行打包时,需要实现将安装包中的某个文件进行替换,而且我们知道在Winodws系统可以有xcopy和copy两个命令可以提供该功能;而xcopy命令进行文件复制时会有如下提示: 此时需要手动输入字…...

睿思BI已支持3D图形
从睿思BI旗舰版V5.3开始,系统支持如下3D图形: 3D地球 3D地图 飞线图 3D金字塔 睿思BI采用ThreeJS实现3D功能,用户也可以基于系统接口,采用ThreeJS在数据大屏中实现自己的3D图形。 系统演示地址:睿思BI旗舰版https://…...
ARCGIS---dem生成高程点
1添加DEM 2在ArcToolbox中点击“3D Analyst工具\转换\由栅格转出\栅格转多点”,调用栅格转多点工具。 3在显示的栅格转多点对话框内,输入栅格选择下载的dem数据,为了保证正常输出,输出要素类最好是默认,方法选择ZTOL…...

2034:D 类音频功率放大器的引脚排列
2034芯片是一款无滤波器5.2W单声道纯D类音频放大器。低EMI适合应用于便携式设备中。 2034芯片的引脚排列: 2034芯片管脚描述: 2034芯片具有关断功能,延长系统的待机时间。过热保护功能增强系统。POP声抑Z功能改进了系统的听觉感受࿰…...

计算机网络第4章-IPv4
IPv4数据报格式 IPv4数据报格式如下图所示 其中,有如下的关键字段需要特别注意: 版本(号): 版本字段共4比特,规定了数据报的IP协议版本。通过查看版本号吗,路由器能确定如何解释IP数据报的剩…...

Transformer的最简洁pytorch实现
目录 前言 1. 数据预处理 2. 模型参数 3. Positional Encoding 4. Pad Mask 5. Subsequence Mask 6. ScaledDotProductAttention 7. MultiHeadAttention 8. FeedForward Networks 9. Encoder Layer 10. Encoder 11. Decoder Layer 12. Decoder 13. Transformer 1…...
【嵌入式开发学习】__u-boot和bootloader到底有什么区别?
目录 前言 一、Bootloader 二、uboot 1. 硬件管理 2. 能够完成镜像烧录(刷机) 3. uboot的“生命周期” 4. uboot要提供命令式shell界面 三、bootloader 与 uboot的区别 (* ̄︶ ̄)创作不易!期待你们的 点赞、收藏…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

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(Direct Memory Access)直接存储器存取 DMA可以提供外设…...