大家好,我是蓝胖子,之前出过一篇https的原理分析 ,完整的介绍了https概念以及通信过程,今天我们就来比较完整的模拟实现https通信的过程,通过这篇文章,你能了解到https核心的概念以及原理,https证书是如何申请的,以及如何用golang实现https通信,https双向认证。

本章代码已经上传到github

https://github.com/HobbyBear/codelearning/tree/master/httpsdemo

https原理回顾

在开始之前,让我们来了解下https相关的核心知识,可以作为上篇https原理分析的补充。学习一个东西一定要先知道为什么要用它,我总结了两点:

1,https 第一个好处是使原本的http明文传输变成了密文传输,增加了安全性。

2,https第二好处是采用数字证书来解决了身份认证问题,起码对端通信是经过ca认证的。

那么https又是通过什么技术来实现上述两点的呢?

数字证书原理

我先聊聊数字证书的实现原理,在https的握手阶段,服务端会发送自身的证书给客户端,客户端会去验证这个证书的有效性,有效性是这样保证的:

数字证书上会写明证书的签名算法和证书的签名,如下图所示

证书经过签名算法中指定的SHA-256算法将证书内容进行hash得到消息摘要,然后再将这个摘要值经过RSA算法用证书颁发机构的私钥进行加密就得到了证书的签名。

而客户端拿到这个证书就会用证书颁发机构的公钥去解密签名,然后按SHA-256算法也对证书内容进行hash,也得到一个消息摘要值,客户端就去比对自己计算的消息摘要和公钥解密签名得到的消息摘要是否一致,一致则说明证书未被篡改并且是证书颁发机构颁发的。

有同学可能会疑惑,证书颁发机构的公钥是从哪里获取的,证书颁发机构的公钥就在颁发机构其自身的证书里,如下图所示。

https密文加密原理

知道了数字证书的验证原理,我们来看看https通信中涉及到的加密过程,在https的握手阶段,服务端会选择一个与客户端都支持的密钥套件用于后续的加密,密钥套件一般会有如下组件:

  1. 密钥交换算法:用于在客户端和服务器之间安全地交换加密密钥。常见的密钥交换算法有RSA和Diffie-Hellman等。

  2. 对称加密算法:用于对通信数据进行加密和解密。常见的对称加密算法有AES、DES和3DES等。

  3. 摘要算法:用于生成和验证消息的完整性。常见的摘要算法有MD5和SHA-256等。

https采用非对称加密的方式交换密钥,然后使用对称加密的方式对数据进行加密,并且对消息的内容采用摘要算法得到消息摘要,这样对端在解密数据后可以通过相同的消息摘要算法对计算后的消息摘要和传过来的消息摘要进行对比,从而判断数据是否经过篡改。

模拟证书颁发

接下来,我们就要开始实现下https的通信了,由于只是实验,我们不会真正的去为我的服务器去申请一个数字证书,所以我们暂时在本地用openssl来模拟下证书颁发的逻辑。

模拟根认证ca机构

我们知道证书颁发的机构是ca,而ca根证书是默认信任的,一般内置在浏览器和操作系统里,所以首先来生成一个根证书,并且让系统默认信任它。

先生成ca的私钥

openssl genpkey -algorithm RSA -out ca_private.key

然后生成ca的证书请求

openssl req -new -key ca_private.key -out ca_csr.csr

生成ca证书

openssl x509 -req -in ca_csr.csr -signkey ca_private.key -out ca_cert.crt

我用的是mac系统,所以我这里演示下mac系统如何添加证书信任,

打开钥匙串应用-> 将证书拖进登录那一栏 -> 右击证书点击显示简介-> 将信任那一栏改为始终信任

模拟ca机构向服务器颁发证书

生成 服务器自身的私钥

openssl genpkey -algorithm RSA -out final_private.key

接着就是生成证书请求,和前面生成证书请求不同,因为目前主流浏览器都要求证书需要设置subjectAltName,如果没有设置SAN会报证书错误。

所以我们要换种方式生成证书请求,首先创建一个文件,比如我创建一个san.txt的文件

[req]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
countryName = country
stateOrProvinceName = province
localityName = city
organizationName = company name
## 换成自己的域名
commonName = lanpangzi.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
## 换成自己的域名
DNS.1=*.lanpangzi.com
DNS.2=*.lanpangzi2.com

到时候上述文件只需要更换为自己的域名即可。由于我的域名设置为了.lanpangzi.com 和.lanpangzi2.com,所以我还要改下本地的hosts文件。

## /etc/hosts
127.0.0.1 www.lanpangzi2.com
127.0.0.1 www.lanpangzi.com

接着生成服务器证书请求

openssl req -new -key final_private.key -out final_csr.csr -config san.txt -sha256

生成服务器证书

openssl x509 -req -days 365 -in final_csr.csr -CA ca_cert.crt -CAkey ca_private.key -set_serial 01 -out final_csr.crt -extfile san.txt -extensions v3_req

golang实现https服务验证证书

经过了上述步骤后算是生成了一个由ca机构颁发的证书,然后我们用golang代码实现一个https服务器。需要为https服务器传入证书以及服务器自身的私钥。

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!\n")
})
fmt.Println(http.ListenAndServeTLS(":443",
"./final_csr.crt",
"./final_private.key", nil))
}

接着实现下客户端代码

func main() {
client := &http.Client{Transport: tr}
resp, err := client.Get("https://www.lanpangzi.com")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

启动服务端和客户端后能看到服务正常返回了。

/private/var/folders/yp/g914gkcd54qdm5d0qyc9ljm00000gn/T/GoLand/___go_build_codelearning_httpsdemo_client
Hello, World!

说明证书配置已经成功,而客户端验证证书的逻辑已经在本文开始讲解了。

golang实现https双向认证

上述代码只是实现了https的单向认证,即客户端对服务端的域名进行认证,在某些情况下,服务端也需要检验客户端是否合法,所以下面我们就来看下如何用golang实现双向认证的。首先我们还是要用ca位客户端颁发一个证书。

模拟ca机构向客户端颁发证书

生成 服务器自身的私钥

openssl genpkey -algorithm RSA -out client_private.key

创建一个san_client.txt的文件

[req]
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
countryName = country
stateOrProvinceName = province
localityName = city
organizationName = company name
## 换成自己的域名
commonName = lanpangziclient.com
[v3_req]
subjectAltName = @alt_names
[alt_names]
## 换成自己的域名
DNS.1=*.lanpangziclient.com
DNS.2=*.lanpangziclient2.com

到时候上述文件只需要更换为自己的域名即可。由于我的域名设置为了.lanpangzi.com 和.lanpangzi2.com,所以我还要改下本地的hosts文件。

## /etc/hosts
127.0.0.1 www.lanpangziclient2.com
127.0.0.1 www.lanpangziclient.com

接着生成服务器证书请求

openssl req -new -key client_private.key -out client_csr.csr -config san_client.txt -sha256

生成服务器证书

openssl x509 -req -days 365 -in client_csr.csr -CA ca_cert.crt -CAkey ca_private.key -set_serial 01 -out client_csr.crt -extfile san_client.txt -extensions v3_req

服务端和客户端需要做下改动,服务端默认不会去校验客户端身份,但是现在改成强制校验

func main() {  

   s := &http.Server{
Addr: ":443",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!\n")
}),
TLSConfig: &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
},
} fmt.Println(s.ListenAndServeTLS("./final_csr.crt",
"./final_private.key"))
}

客户端代码请求时需要带上自己的证书

func main() {
cliCrt, err := tls.LoadX509KeyPair("./client_csr.crt", "./client_private.key")
if err != nil {
fmt.Println("Loadx509keypair err:", err)
return
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{
Certificates: []tls.Certificate{cliCrt},
},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://www.lanpangzi.com")
if err != nil {
fmt.Println("Get error:", err)
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}

这样就完成了一个https的双向认证。

https 原理分析进阶-模拟https通信过程的更多相关文章

  1. HTTPS 原理分析——带着疑问层层深入

    HTTPS 随着 HTTPS 建站的成本下降,现在大部分的网站都已经开始用上 HTTPS 协议.大家都知道 HTTPS 比 HTTP 安全,也听说过与 HTTPS 协议相关的概念有 SSL .非对称加 ...

  2. HTTPS原理分析

    引言 随着互联网安全意识的普遍提高,对安全要求稍高的应用中,HTTPS的使用是很常见的,所以,无论是即时通讯IM还是其它应用,在网络安全意识增强的今天,很多场景下使用HTTPS是肯定没错的.对于即时通 ...

  3. https原理及tomcat配置https方法

    一. 什么是HTTPS 在说HTTPS之前先说说什么是HTTP,HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不 ...

  4. (HTTPS)-https原理及tomcat配置https方法

    一. 什么是HTTPS 在说HTTPS之前先说说什么是HTTP,HTTP就是我们平时浏览网页时候使用的一种协议.HTTP协议传 输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常 ...

  5. https原理和如何配置https

    参考:https://blog.51cto.com/11883699/2160032 上面说的已经很好地,我这里简单做个总结: 在网上我们做数据交互时候一般用的http协议,但是这种方式会使得交互内容 ...

  6. Charles的HTTPS抓包方法及原理分析

    原文地址:http://www.jianshu.com/p/870451cb4eb0 背景 作为移动平台的RD,项目开发过程中一项比较重要的甩锅技能——抓包应该大家都比较熟悉了,毕竟有些bug可能是由 ...

  7. 【转】HTTPS系列干货(一):HTTPS 原理详解

    HTTPS系列干货(一):HTTPS 原理详解 前言 HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer),其实 HTTPS 并 ...

  8. web压测工具http_load原理分析

    一.前言 http_load是一款测试web服务器性能的开源工具,从下面的网址可以下载到最新版本的http_load: http://www.acme.com/software/http_load/ ...

  9. Mybatis 原理分析

    对于入门程序的流程分析 使用过程 读配置文件 读取配置文件时绝对路径和相对路径(web工程部署后没有src路径)都有一定问题,实际开发中一般有两种方法 使用类加载器,它只能读取类路径的配置文件 使用S ...

  10. 从wireshake分析http和https的通信过程

    参考文章: Wireshark基本介绍和学习TCP三次握手 [技术流]Wireshark对HTTPS数据的解密 Wireshark/HTTPS Journey to HTTP/2 以TCP/IP协议为 ...

随机推荐

  1. [Windows]CMD命令入门教程 与 Windows常见维护问题

    本博文最早是记录在本地电脑的,由于清理电脑的缘故,顺便将这篇笔记转移到公共博客,以便日后查阅和快速上手使用. 开门见山,步入正题,以下是Windows系统的常用CMD命令. ----2018-03-2 ...

  2. React+Antd在使用form表单提交DatePicker日期框的时候会出现少八小时的情况

    在使用antd做form表单提交的时候,突然发现了一个很有意思的bug.就是在使用datepicker组件日期框的时候会出现提交后少一天的问题 我在网上搜索了许多解决办法,也是困扰了我一天的时间,下面 ...

  3. pdf 转 word

    目录 pdf 转 word 一.思路 二.软件安装下载 1. windows安装 2 certos7版本安装 3. Debian 版本安装 4. 安装字体 三.实现PDF转word文档 四.制作自己的 ...

  4. [OpenCV-Python] 20 图像金字塔

    文章目录 OpenCV-Python:IV OpenCV中的图像处理 20 图像金字塔 20.1 原理 20.2 使用金字塔进行图像融合 OpenCV-Python:IV OpenCV中的图像处理 2 ...

  5. 【解决方法】正常游览Flash页面,解决主流游览器的不支持问题(如Edge,Firefox)

    环境: 工具:360游览器-某特殊版本 系统版本:Windows 10 视频链接:[[解决方法]正常浏览flash页面,解决主流浏览器的不支持问题] https://www.bilibili.com/ ...

  6. Istio数据面新模式:Ambient Mesh技术解析

    摘要:Ambient Mesh以一种更符合大规模落地要求的形态出现,克服了大多数Sidecar模式的固有缺陷,让用户无需再感知网格相关组件,真正将网格下沉为基础设施. 本文分享自华为云社区<华为 ...

  7. BugKu_never_give_up

    if(!$_GET['id']) { header('Location: hello.php?id=1'); exit(); } $id=$_GET['id']; $a=$_GET['a']; $b= ...

  8. Vulhub activewq_漏洞复现——源码分析

    Vulhub activewq_漏洞复现--源码分析 漏洞简介 Apache ActiveMQ是由美国阿帕奇(Apache)软件基金会开发的开源消息中间件,支持Java消息服务.集群.Spring框架 ...

  9. Linux xfs文件系统stat命令Birth字段为空的原因探究

    在Linux平台找出某个目录下创建时间最早的文件,测试验证脚本结果是否准确的过程中发现一个很有意思的现象,stat命令在一些平台下Birth字段有值,而在一些平台则为空值,如下所示: RHEL 8.7 ...

  10. 文心一言 VS chatgpt (9)-- 算法导论2.3 7题 3.1 1题

    七.描述一个运行时间为O(nlgn)的算法,给定n个整数的集合S和另一个整数,该算法能确定 S中是否存在两个其和刚好为工的元素. 文心一言: 这里是一个运行时间为O(nlgn)的算法,可以用来确定集合 ...