惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tenable Blog
Project Zero
Project Zero
T
The Exploit Database - CXSecurity.com
T
Threat Research - Cisco Blogs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cyberwarzone
Cyberwarzone
PCI Perspectives
PCI Perspectives
G
GRAHAM CLULEY
H
Hacker News: Front Page
Cloudbric
Cloudbric
Latest news
Latest news
N
News and Events Feed by Topic
C
CERT Recently Published Vulnerability Notes
Attack and Defense Labs
Attack and Defense Labs
SecWiki News
SecWiki News
Security Latest
Security Latest
MyScale Blog
MyScale Blog
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Security Archives - TechRepublic
Security Archives - TechRepublic
V2EX - 技术
V2EX - 技术
B
Blog RSS Feed
L
LINUX DO - 最新话题
人人都是产品经理
人人都是产品经理
Last Week in AI
Last Week in AI
IT之家
IT之家
Jina AI
Jina AI
Y
Y Combinator Blog
博客园 - 聂微东
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
P
Privacy International News Feed
B
Blog
S
Schneier on Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
Help Net Security
Help Net Security
D
DataBreaches.Net
博客园_首页
G
Google Developers Blog
I
InfoQ
量子位
大猫的无限游戏
大猫的无限游戏
S
Security @ Cisco Blogs

元视角

.NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角 为你的服务器集成 LDAP 认证 - 元视角 似花还似非花 - 元视角 视频是不能 P 的系列:使用 Dlib 实现人脸识别 - 元视角 浅议分布式链路追踪与日志的整合 - 元视角 关于 Git 大文件上传这件小事 - 元视角 .NET 进程内队列 Channel 的入门与应用 - 元视角 使用 Fody 实现 .NET 的静态编织 - 元视角 .NET Core + ELK 搭建可视化日志分析平台(下) - 元视角 聊一聊前端图片懒加载背后的故事 - 元视角 支持外部链接跳转的 Vue Router 扩展实现 - 元视角 视频是不能 P 的系列:OpenCV 和 Dlib 实现表情包 - 元视角 不得不说的 ASP.NET Core 集成测试 - 元视角 再议 DDD 视角下的 EFCore 与 领域事件 - 元视角 Vue.js 前端项目容器化部署实践极简教程 - 元视角 再见,人间四月天 - 元视角 Python 图像风格化迁移助力画家梦想 - 元视角 利用 ASP.NET Core 中的标头传播实现分布式链路追踪 - 元视角 利用 gRPC 实现文件的上传与下载 - 元视角 七种武器:延迟队列的原理和实现总结 - 元视角 gRPC 流式传输极简入门指南 - 元视角 Envoy 集成 Jaeger 实现分布式链路追踪 - 元视角 浅议非典型 Web 应用场景下的身份认证 - 元视角 gRPC 借助 Any 类型实现接口的泛化调用 - 元视角 分布式丛林探险系列之 Redis 集群模式 - 元视角 分布式丛林探险系列之 Redis 主从复制模式 - 元视角 通过 Python 预测 2021 年双十一交易额 - 元视角 gRPC 搭配 Swagger 实现微服务文档化 - 元视角 SSL/TLS 加密传输与数字证书的前世今生 - 元视角 使用 Python 自动识别防疫健康码 - 元视角 你不可不知的容器编排进阶技巧 - 元视角 ASP.NET Core 搭载 Envoy 实现 gRPC 服务代理 - 元视角 再话 AOP,从简化缓存操作说起 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT) - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的监控预警 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的反向代理 - 元视角 ASP.NET Core gRPC 打通前端世界的尝试 - 元视角 EFCore 实体命名约定库:EFCore.NamingConventions - 元视角 ASP.NET Core gRPC 集成 Polly 实现优雅重试 - 元视角 ASP.NET Core gRPC 健康检查的探索与实现 - 元视角 ASP.NET Core gRPC 拦截器的使用技巧分享 - 元视角 SnowNLP 使用自定义语料进行模型训练 - 元视角 使用 HttpMessageHandler 实现 HttpClient 请求管道自定义 - 元视角 ABP vNext 的实体与服务扩展技巧分享 - 元视角 ABP vNext 对接 Ant Design Vue 实现分页查询 - 元视角 源代码探案系列之 .NET Core 跨域中间件 CORS - 元视角 源代码探案系列之 .NET Core 限流中间件 AspNetCoreRateLimit - 元视角 源代码探案系列之 .NET Core 并发限制中间件 ConcurrencyLimiter - 元视角 通过 EmbededFileProvider 实现 Blazor 的静态文件访问 - 元视角 低代码,想说爱你不容易 - 元视角 记一次失败的 ThoughtWorks 面试经历 - 元视角 从 C# 1.0 到 C# 9.0,历代 C# 语言特性一览 - 元视角 通过 Python 分析 2020 年全年微博热搜数据 - 元视角 基于 Python 和 Selenium 实现 CSDN 一键三连自动化 - 元视角 使用多线程为你的 Python 爬虫提速的 N 种姿势,你会几种? - 元视角 实现网页长截图的常见思路总结 - 元视角 温故而知新,由 ADO.NET 与 Dapper 所联想到的 - 元视角 视频是不能 P 的系列:OpenCV 人脸检测 - 元视角 作为技术宅的我,是这样追鬼滅の刃的 - 元视角 使用 Python 抽取《半泽直树》原著小说人物关系 - 元视角 厉害了!打工人用 Python 分析西安市职位信息 - 元视角 使用 dotTrace 对 .NET 应用进行性能分析与优化 - 元视角 一道 HashSet 面试题引发的蝴蝶效应 - 元视角 基于选项模式实现.NET Core 的配置热更新 - 元视角 Dapper.Contrib 在 Oracle 环境下引发 ORA-00928 异常问题的解决 - 元视角 .NET Core 中对象池(Object Pool)的使用 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(下):EventBus 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(中):RabbitMQ 篇 - 元视角 利用 MySQL 的 Binlog 实现数据同步与订阅(上):基础篇 - 元视角 记一次从已损坏的 Git 仓库中找回代码的经历 - 元视角 .NET Core 原生 DI 扩展之属性注入实现 - 元视角
使用 C#开发 HTTP 服务器之支持 HTTPS - 元视角
飞鸿踏雪 · 2017-03-05 · via 元视角

各位朋友大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com。本文是“使用 C#开发 HTTP 服务器”系列的第六篇文章,在这个系列文章中我们实现了一个基础的 Web 服务器,它支持从本地读取静态 HTML 页面,支持 GET 和 POST 两种请求方式。该项目托管在我的Github上,项目地址为https://github.com/qinyuanpei/HttpServer,感兴趣的朋友可以前往了解。其间有朋友为我提供了 HTTPS 的 PR,或许这偏离了这个系列开发 HTTP 服务器的初衷,可是我们应该认识到普及 HTTPS 是大势所趋。所以在今天这篇文章中,我将为大家带来 HTTPS 相关知识的普及,以及如何为我们的这个 Web 服务器增加 HTTPS 的支持。

2017 年我们听到这样一个声音,苹果将强制实施 ATS,即 App Transport Security。首先我们要了解的是 ATS,它是苹果为了保证应用数据在网络中安全地传输而制定的一种规则,其核心是鼓励开发者使用安全的 HTTPS 协议和服务器进行通讯。在此之前考虑到大量的应用还在使用 HTTP 协议,所以苹果并未强制要求应用遵守这个规范,而此时苹果发出这样一种声音,我们终于意识到苹果这是在推广 HTTPS 啊!无独有偶,同样作为科技巨头之一的 Google,宣布在新发布的 Chrome 56 中会将仅支持 HTTP 协议的网页标记为“不安全”。HTTPS 到底是什么呢?为什么科技巨头纷纷开始对它青眼有加呢?这或许要从 HTTPS 协议说起。

HTTPS,即 Hyper Text Transfer Protocol Over Secure Socket Layer 的简称,是指以安全为目标的 HTTP 协议。我们可以将其理解为在 HTTP 协议的基础上增加了安全机制,这里的安全机制是指 SSL,简单来讲 HTTPS 协议依然采用 HTTP 协议,不过它在 HTTP 和 TCP 间增加了加密/身份验证层,因此在保证数据传输安全的同时,为服务器提供了身份校验机制。任何采用 HTTPS 协议的网站,均可通过浏览器地址栏中的“锁”标志来查看网站的认证信息,或者是通过 CA 机构颁发的数字证书来查询。下图展示的是 HTTPS 协议中客户端和服务器端通信过程:

HTTPS协议中客户端和服务器通信过程 HTTPS协议中客户端和服务器通信过程

从图中我们可以看出,在 HTTPS 协议中客户端和服务器端分为六步:

  • 客户端请求服务器,发送握手消息给服务器。
  • 服务器端返回客户端加密算法、数字证书和公钥。
  • 客户端对返回的数字证书进行验证,如果验证通过则产生一个随机数,否则提示验证失败。
  • 客户端使用公钥对产生的随机数进行加密,然后将其发送给服务器端。
  • 服务器对该随机数进行解密,并以此作为密钥发送握手信息给客户端。
  • 客户端收到消息后对消息进行解密,如果解密成功则表示握手结束。

这恰恰印证了我们最初的观点,即 HTTPS 协议依然采用 HTTP 协议(三次握手)进行通讯,不同的地方在于中间环节增加了加密处理,例如在客户端和服务器端相互验证的环节采用的是非对称加密,在客户端验证通过以后双方采用随机数作为密钥是对称加密,而三次握手以后验证消息是否被篡改则是采用 HASH 算法。所以我们应该可以注意到,HTTP 协议和 HTTPS 协议的一个显著的区别是,前者采用明文来传输消息,而后者采用密文来传输消息,因此 HTTPS 协议比 HTTP 协议在通讯上更为安全。而详细来说,两者的区别主要有:

  • HTTPS 需要证书,而 HTTP 则不需要证书,证书由 CA 机构颁发。
  • HTTP 采用明文来传输消息,C/S 端无身份验证;HTTPS 采用密文来传输消息,C/S 端有身份验证。
  • HTTP 默认采用 80 端口进行通信,而 HTTPS 默认采用 443 端口进行通信。

好了,现在我们对 HTTPS 协议有了一个基本的认识:HTTPS 协议相比 HTTP 协议增加了身份验证和消息加密的机制,因此 HTTPS 协议能够保证通讯过程中的数据传输安全。在今天这样一个数字时代,当个人隐私安全彻底地暴露在浏览器、应用程序面前,能够提供更安全的互联网服务无疑会让人更有安全感,我想这是苹果和谷歌这样的科技巨头公司,之所以要去努力推广 HTTPS 协议的原因吧!因为客户端需要对服务器的证书进行验证,所以这意味着在客户端拥有访问所有受信证书的能力,例如我们在使用传统网银产品时都需要安装网银证书,这其实就是为了让客户端在向服务器端发起请求时方便对服务器进行验证,因此如果客户端请求的 URL 遭遇劫持,被重定向到某个不被信任的站点上,那么客户端发起的请求就会被拦截。同样的道理,服务器端会对客户端的请求进行验证,所以这里就不再详细展开去说啦。

我们最初设计这个 HTTP 服务器的时候,没有考虑过要支持 HTTPS 协议。可是当我们了解了 HTTPS 协议后,我们发现,如果要让最初设计的 Web 服务器支持 HTTPS 协议,我们需要关注的是 Security,即身份验证和数据加密,我们知道这里的 Security 指的是 SSL,所以需要了解 SSL 相关的内容。其次,我们需要提供一个数字证书给服务器端,目的是在客户端发起请求的时候,将数字证书、加密算法和公钥返回,保证客户端可以完成证书校验。从这两点可以看出,我们首先需要从 CA 机构购买证书,这一点毋庸置疑。关于证书的购买及服务器的设置,我们通过搜索引擎可以找到相关参考。目前主流的服务器如 Apache、IIS、Tomcat 和 Ngnix 都可以非常方便地支持 HTTPS,这些问题更像是一种基础设施,所以我会在文章末尾列举出相关文章供大家查阅。

这篇文章的核心是开发一个服务器,所以在保证这些基础设施完备的前提下,让我们将关注点落实到代码上面来。我们提到,HTTPS 除了证书以外关键点是 SSL,而在.NET 中提供 SSL 相关的 API,所以这里我们直接使用这些 API 就可以完成证书的创建、加载等工作。下面是相关的代码示例:

// 使用OpenSSL.NET生成密钥
RSA rsa = new RSA();
BigNumber number = OpenSSL.Core.Random.Next(10, 10, 1);
rsa.GenerateKeys(1024, number, null, null);
CryptoKey key = new CryptoKey(rsa);

//创建X509证书,Subject和Issuer相同 
X509Certificate x509 = new X509Certificate();
x509.SerialNumber = (int)DateTime.Now.Ticks;
x509.Subject = new X509Name("CN=DOMAIN");        //DOMAIN为站点域名 
x509.Issuer = new X509Name("CN=DOMAIN");
x509.PublicKey = key;                            //指定公钥 
x509.NotBefore = Convert.ToDateTime("2011-1-1"); //起始时间 
x509.NotAfter = Convert.ToDateTime("2050-1-1");  //失效时间 
x509.Version = 2;

//使用私钥签名
x509.Sign(key, MessageDigest.MD5);

//生成CRT证书
BIO x509bio = BIO.File("CA.crt", "w");
x509.Write(x509bio);

//生成PFX证书
var certs = new OpenSSL.Core.Stack<X509Certificate>();
PKCS12 p12 = new PKCS12("PASSWORD", key, x509, certs); //PASSWORD为保护密钥 
BIO p12Bio = BIO.File("CA.pfx", "w");
p12.Write(p12Bio);

//加载证书
var certifiate = X509Certificate.CreateFromCertFile("CA.crt");

在我们获得证书以后,我们就可以通过 SSL 对 Socket 通信过程中传递的消息进行加密了,一个基本的示例代码如下:

SslStream sslStream = new SslStream(clientStream);
sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls, true);
sslStream.ReadTimeout = 10000;
sslStream.WriteTimeout = 10000;
return sslStream;

个人感觉加密相关的问题深奥而晦涩,这篇文章中涉及到的相关概念和技术,都大大地超出了我目前的认知范围。不过既然这位朋友热心地提交了这个 PR,我就将这个过程视为向别人的一次学习吧!我会继续去完善这个项目:https://github.com/qinyuanpei/HttpServer。这篇博客终于算是写完了,周末开心!

参考文章