flutter 中 ssl 双向证书校验

SSL 证书:

        在处理 https 请求的时候,通常可以使用 中间人攻击的方式   获取 https 请求以及响应参数。应为通常我们是 SSL 单向认证,服务器并没有验证我们的客户端的证书。为了防止这种中间人攻击的情况。我么可以通过 ssl 双向认证的方式。即服务端要验证客户端请求的证书合法性。

SSL 单向认证

      

        无需客户端拥有证书,只需服务端拥有证书  客户端也需要验证服务端证书;SSL 单向认证相对于 SSL 双向认证的认证过程,无需在服务端验证客户端证书、以及协商加密方案,服务端发送给客户端也是未加密的密码方案(并不影响 SSL 认证过程的安全性)

SSL 双向认证


        需要客户端 和 服务端双方都拥有证书。并且验证是双向的,即服务端 需要验证 客户端证书,客户端也需要验证服务端证书。当然服务器 也需要开启认证 客户端证书的操作并且证书如果放在客户端 如何保证证书的安全性也是一个很好的话题,否则意义不会太大

生成 客户端 ssl 证书

因为 Flutter 不支持 .p12 格式的,这里需要生成  .pem 格式的证书

1. 准备环境

        首先,确保你已经安装了 OpenSSL 工具。OpenSSL 是处理证书的常用工具,可以在大多数操作系统上安装。

2. 生成客户端证书密钥对

客户端证书需要一个公私钥对。首先,你需要生成一个私钥文件 过程需要输入秘钥

openssl genpkey -algorithm RSA -out client_key.pem -aes256# client_key.pem 是你生成的私钥文件。-aes256 参数表示私钥文件将使用 AES-256 加密。
3. 创建客户端证书签名请求 (CSR)

使用生成的私钥来创建一个客户端证书签名请求(CSR):

openssl req -new -key client_key.pem -out client_csr.pem#在执行这个命令时,你需要提供一些信息,例如国家、州、城市、组织名等。这些信息将被包含在 CSR 中。

4. 签署客户端证书
选项 1: 使用自签名证书

如果你使用自签名证书(即没有使用正式的 CA),可以通过 OpenSSL 自行签署客户端证书:

首先,生成一个自签名证书:

openssl x509 -req -in client_csr.pem -signkey client_key.pem -out client_cert.pem##### 这个证书是自签名的,仅在你的环境中有效,不适用于生产环境。

选项 2: 通过服务端证书签署

如果你希望使用服务端证书签署客户端证书通常服务端证书由一个 CA 签发 即你服务器SSL 证书提供商,你需要以下步骤:

  • 将客户端 CSR 提交给 CA: 将 client_csr.pem 提交给负责签署客户端证书的 CA。CA 将使用其私钥来签署客户端 CSR,生成一个客户端证书。

  • CA 签署客户端证书: CA 使用它的私钥对 CSR 进行签名,生成客户端证书。假设 CA 使用 ca-cert.pemca-key.pem 文件签署证书,你可以使用如下命令

openssl x509 -req -in client_csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client_cert.pem -days 365##这里,ca-cert.pem 是 CA 的证书,ca-key.pem 是 CA 的私钥,-CAcreateserial 参数表示如果没有 CA 序列号文件,则创建一个。

Flutter 中使用客户端 ssl 证书

如果是全局配置:main.dart 中

HttpOverrides.global = await AppHttpCert().createHttpProxy();

核心代理就这里:

///证书校验,Flutter  暂不支持 .p12
@override
HttpClient createHttpClient(SecurityContext? context) {// TODO: implement createHttpClient//return super.createHttpClient(context);final securityContext = SecurityContext(withTrustedRoots: false)..useCertificateChainBytes(clientCert.buffer.asUint8List(),password: 'https://pan.baidu.com/j/1WtKrUBVVZS')..usePrivateKeyBytes(clientKey.buffer.asUint8List(),password: 'https://pan.baidu.com/j/1WtKrUBVVZS');HttpClient client = super.createHttpClient(securityContext);client.badCertificateCallback = _badCertificateCallback;return client;
}///用于处理不受信任的证书。通过这个回调函数,你可以根据自定义逻辑决定是否接受一个不受信任的证书
bool _badCertificateCallback(X509Certificate cert, String host, int port) {// 打印证书信息print('Received certificate from host: $host, port: $port');print('Certificate subject: ${cert.subject}');print('Certificate issuer: ${cert.issuer}');print('Certificate valid from: ${cert.startValidity}');print('Certificate valid until: ${cert.endValidity}');// return true;if (kReleaseMode) {return false;} else {return true;}
}

完整代码:因为我这里在开发阶段使用代理抓包,不需要的可以直接略过

import 'dart:io';import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';class AppHttpCert {String? host;String? port;MethodChannel _channel = MethodChannel('com.lm.http.proxy');Future<String?> _getProxyHost() async {return await _channel.invokeMethod('getProxyHost');}Future<String?> _getProxyPort() async {return await _channel.invokeMethod('getProxyPort');}Future<AppHttpOverrides> createHttpProxy() async {final clientCert = await rootBundle.load('assets/client_cert.pem');final clientKey = await rootBundle.load('assets/client_key.pem');final String? host = await _getProxyHost();final String? port = await _getProxyPort();return AppHttpOverrides(clientCert: clientCert,clientKey: clientKey,host: host,port: port,);}
}class AppHttpOverrides extends HttpOverrides {final String? host;final String? port;final ByteData clientCert;final ByteData clientKey;AppHttpOverrides({required this.clientCert,required this.clientKey,required this.host,required this.port});///证书校验,暂不支持 .p12@overrideHttpClient createHttpClient(SecurityContext? context) {// TODO: implement createHttpClient//return super.createHttpClient(context);final securityContext = SecurityContext(withTrustedRoots: false)..useCertificateChainBytes(clientCert.buffer.asUint8List(),password: 'https://pan.baidu.com/j/1WtKrUBVVZS')..usePrivateKeyBytes(clientKey.buffer.asUint8List(),password: 'https://pan.baidu.com/j/1WtKrUBVVZS');// // 设置受信任的服务器证书// securityContext//     .setTrustedCertificatesBytes(serverCert.buffer.asUint8List());HttpClient client = super.createHttpClient(securityContext);client.badCertificateCallback = _badCertificateCallback;return client;}///用于处理不受信任的证书。通过这个回调函数,你可以根据自定义逻辑决定是否接受一个不受信任的证书bool _badCertificateCallback(X509Certificate cert, String host, int port) {// 打印证书信息print('Received certificate from host: $host, port: $port');print('Certificate subject: ${cert.subject}');print('Certificate issuer: ${cert.issuer}');print('Certificate valid from: ${cert.startValidity}');print('Certificate valid until: ${cert.endValidity}');// return true;if (kReleaseMode) {return false;} else {return true;}}///是否使用代理@overrideString findProxyFromEnvironment(Uri url, Map<String, String>? environment) {// TODO: implement findProxyFromEnvironmentif (host == null) {return super.findProxyFromEnvironment(url, environment);}environment ??= {};if (port != null) {environment['http_proxy'] = '$host:$port';environment['https_proxy'] = '$host:$port';} else {environment['http_proxy'] = '$host:8888';environment['https_proxy'] = '$host:8888';}return super.findProxyFromEnvironment(url, environment);}
}

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

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

相关文章

用Python实现时间序列模型实战——Day1:时间序列的基本概念

一、学习内容 1. 时间序列数据的定义与特点 定义&#xff1a; 时间序列数据是一组按时间顺序排列的观测值。时间序列的每个观测值都与特定时间点相关联。例如&#xff0c;气温每天的记录、股票每日的收盘价等。 特点&#xff1a; 时间依赖性&#xff1a;时间序列数据的一个…

Eureka的生命周期管理:服务注册、续约与下线的完整流程解析

Eureka的生命周期管理&#xff1a;服务注册、续约与下线的完整流程解析 引言 在分布式系统中&#xff0c;服务发现是微服务架构的核心问题之一。Eureka是Netflix开源的一个服务发现框架&#xff0c;它能够有效地管理微服务的生命周期&#xff0c;包括服务注册、续约和下线。这…

8.27-dockerfile的应用+私有仓库的创建

一、dockerfile应用 通过dockerfile创建⼀个在启动容器时&#xff0c;就可以启动httpd服务的镜像 1.步骤 : 1.创建⼀个⽬录&#xff0c;⽤于存储Docker file所使⽤的⽂件2.在此⽬录中创建Docker file⽂件&#xff0c;以及镜像制作所使⽤的⽂件3.使⽤docker build创建镜像4.使…

基于x86 平台opencv的图像采集和seetaface6的图像质量评估功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.3 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的图像质量评估功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的图像质量评估模块…

全新的大语言模型Grok-2,最新测评!!

埃隆马斯克再次引发轰动&#xff0c;他旗下的xAI公司推出了全新的大语言模型Grok-2&#xff01; 最新的Grok-2测试版已经发布&#xff0c;用户可以在&#x1d54f;平台上体验小版本的Grok-2 mini。 马斯克还通过一种谜语般的方式揭开了困扰大模型社区一个多月的谜团&#xff1a…

Java笔试面试题AI答之面向对象(2)

文章目录 7. Java中的组合、聚合和关联有什么区别&#xff1f;1. 关联&#xff08;Association&#xff09;2. 聚合&#xff08;Aggregation&#xff09;3. 组合&#xff08;Composition&#xff09;总结 8. 请设计一个符合开闭原则的设计模式的例子&#xff1f;策略模式示例1.…

每日刷力扣SQL(九)

1484.按日期分组销售产品 转载 首先&#xff0c;根据题目的描述以及给出的示例。我们能得到结果集中各个字段的含义如下&#xff1a; ① sell_date&#xff1a;卖出产品的日期&#xff08;应该不用解释了&#xff09; ② num_sold&#xff1a;当前这个日期下&…

工业软件架构2:(QT和C++实现)

工业软件架构 - 事件驱动 - 2 1. 命令模式的使用命令模式(Command Pattern)命令模式的基本概念命令模式的运作机制1. 定义命令接口2. 实现具体命令3. 调用者类4.扩展命令模式的功能撤销命令:宏命令:总结2. MVVM 模式的使用View(界面)部分则通过绑定与 ViewModel 交互:3.…

FFmpeg的入门实践系列三(基础知识)

欢迎诸位来阅读在下的博文~ 在这里&#xff0c;在下会不定期发表一些浅薄的知识和经验&#xff0c;望诸位能与在下多多交流&#xff0c;共同努力 文章目录 前期博客一、音视频常用术语二、FFmpeg库的结构介绍三、FFmpeg的常用函数初始化封装格式编解码器相关 四、FFmpeg常用的数…

FastCGI简述

FastCGI (FCGI) 是一种协议&#xff0c;用于改善 Web 服务器和应用程序之间的通信效率。它是在 CGI&#xff08;Common Gateway Interface&#xff09;的基础上发展起来的&#xff0c;旨在解决 CGI 在处理大量并发请求时存在的性能问题。 CGI的由来 最早的Web服务器只能简单地…

WHAT - Jamstack(JavaScript, APIs, and Markup 与 Serverless 无服务器架构)

目录 一、介绍1. JavaScript2. APIs3. Markup4. Jamstack 的优势5. Jamstack 架构的工作流程 二、常见的 Jamstack 技术栈三、无服务器架构&#xff08;Serverless&#xff09;无服务器架构的核心概念1. 函数即服务&#xff08;FaaS&#xff09;2. 后端即服务&#xff08;BaaS&…

解决 JS WebSocket 心跳检测 重连

解决 JS WebSocket 心跳检测 重连 文章目录 解决 JS WebSocket 心跳检测 重连一、WebSocket 心跳检测的作用二、心跳检测的处理方案1. 创建 WebSocket 连接2. 心跳参数设置3. 心跳检测逻辑4. 心跳包响应处理5. 断线重连机制 三、总结 一、WebSocket 心跳检测的作用 WebSocket 是…

序列化组件对比

1、msgpack介绍 1.MsgPack产生的数据更小&#xff0c;从而在数据传输过程中网络压力更小 2.MsgPack兼容性差&#xff0c;必须按照顺序保存字段 3.MsgPack是二进制序列化格式&#xff0c;兼容跨语言 官网地址&#xff1a; https://msgpack.org/ 官方介绍&#xff1a;Its lik…

C++ 移动构造函数为什么设置noexcept?

答案显然是&#xff1a; 移动构造函数设置了noexcept后STL的容器可以显著提高性能。 For example: class MyClass { public:MyClass(int v) { val v; }MyClass(const MyClass& o) {val o.val;std::cout << "Copy constructor " << val << …

Go 语言协程管理精解

1.基础 协程切换需要操作寄存器&#xff0c;这些操作需要通过汇编辅助实现。另外&#xff0c;每一个协程都有一个协程栈&#xff0c;实际上协程栈也是有结构的。汇编程序和栈结构这些概念可能大部分开发者都不太了解&#xff0c;在介绍协程管理之间&#xff0c;先简要介绍。 1…

一、undo log、Buffer Pool、WAL、redo log

目录 1、undo log2、Buffer Pool3、WAL4、redo log5、总结6、问题 1、undo log undo log日志是一种用于撤销回退的逻辑日志&#xff0c;在事务未提交前会记录相反的操作到undo log&#xff0c;当事务回滚&#xff0c;使用undo log 进行回滚&#xff0c;保证了事务的原子性。MV…

【生活英语】1、高兴与难过

【生活英语】1、高兴与难过 一、我非常非常开心二、心情三、不开心四、运气五、英语对话1、We broke up2、中奖了 一、我非常非常开心 (1) I’m really happy. (2) I’m really overjoyed. (3) I couldn’t be happier. I couldn’t agree with you more. 我非常赞同你。 (4) …

C++ TinyWebServer项目总结(8. 高性能服务器程序框架)

《Linux 高性能服务器编程》一书中&#xff0c;把这一章节作为全书的核心&#xff0c;同时作为后续章节的总览。这也意味着我们在经历了前置知识的学习后&#xff0c;正式进入了 Web 服务器项目的核心部分&#xff01; 前置内容回顾&#xff1a; 1. C TinyWebServer项目总结&…

每日一问:GET请求和POST请求的区别

每日一问&#xff1a;GET请求和POST请求的区别 在Web开发中&#xff0c;GET请求和POST请求是最常见的两种HTTP请求方法。尽管它们在功能上有许多相似之处&#xff0c;但在使用场景、数据传递方式、缓存策略等方面存在显著差异。了解这些区别不仅有助于我们在开发中做出正确的选…

Docker拉取镜像-2024-07-有效

Docker拉取镜像-有效 配置加速地址 首先&#xff0c;创建Docker配置目录&#xff1a;sudo mkdir -p /etc/docker然后&#xff0c;编辑daemon.json文件&#xff0c;添加以下加速地址&#xff1a;sudo tee /etc/docker/daemon.json <<-EOF {"registry-mirrors"…