使用自签证书利用浏览器进行HTTPS接口的安全访问

HTTPS的基本工作原理想必对于许多开发者来说是非常熟悉的了,我们一起先回忆一下HTTP常见的八股文中的描述:

  1. 客户端(浏览器)访问 HTTPS 的URL;
  2. 服务器返回 HTTPS 使用的 CA 证书;
  3. 客户端(浏览器)验证 CA 证书是否为合法证书;
  4. 验证通过,证书合法,生成一串随机数并使用公钥(证书中提供的)进行加密;
  5. 发送公钥加密后的随机数给服务器;
  6. 服务器拿到密文,通过私钥进行解密,获取到随机数(公钥加密,私钥解密,反之也可以);
  7. 服务器把要发送给浏览器的内容,使用随机数进行加密后传输给客户端(浏览器);
  8. 此时客户端(浏览器)可以使用随机数进行解密,获取到服务器的真实传输内容。

大体的过程是这样的,从整个过程中可以看出来,整个流程中涉及到了多个交互过程,主要分为了客户端、浏览器、以及CA之间的交互,还是比较复杂的,尤其是要具体知道每一步骤的其中细节,也是非常多的内容,所以这篇文章不是要去分析每一步的工作机制和原理,这篇文章主要内容是如何使用自签证书完成这一个过程,从而使我们能够进一步的对其有个初步的认识,如果对这其中细节感兴趣的,可以自行学习下,或者可能之后我也会对其进行深入的研究再和大家分享学习。

那么我们回到我们的主题里,首先需要知道CA证书是什么,CA是证书颁发机构(Certificate Authority)的缩写,那么CA证书就是证书机构颁发的一种数字证书,为什么需要这个机构来颁发证书呢?可以理解为就是一个第三方担保机构,这个担保机构保证了在客户端和服务器的通讯阶段的安全,这样客户端只要是看到证书是这个担保机构担保过的,那就会认可这个服务器并和它进行后续交互,反之其他证书都是不合法的,不会进行更进一步的交互了。

其次,这个证书不光是用来证明其合法性,其中还包含了一个公钥,公钥是什么呢?这边就涉及到一些密码学相关知识点了,我们需要先知道非对称加密的一点概念,可以猜出来,有非对称加密那肯定有对称加密,对称加密就是使用同一把密钥进行加密和解密,而非对称加密会用到2个密钥,一把公钥和一把私钥进行加密和解密,公钥会公开出去给客户端,而私钥会保存在本地防止泄漏,所以会更安全,使用这个公钥加密后的数据可以被私钥解开,反过来也是一样的,在上面的HTTPS的连接过程中,1-6步骤所涉及到的就是非对称加解密过程,而后续则会采用对称加密的方式,即使用一个随机数充当了对称加密的密钥进行了通讯,这样一方面是为了提高通讯的效率更重要的是为了保证安全,因为如果还使用原有的公钥和私钥的方式在服务端使用私钥加密,那么只要有公钥的客户端都可以截获服务端发来的信息进行解密,显然这样是不行的。对加密感兴趣的小伙伴可以自行百度看看,这边先不展开了。

知道了概念后,那自签证书的概念就是我们自己充当这个CA机构给自己颁发一个证书,然后想办法让客户端信任这个证书(一般的默认做法是系统会有一个受信任的证书列表,其中就会有存放一些CA机构的根证书),并且证书里面包含了我们的公钥,客户端使用这个公钥进行数据加密,再传输数据,服务端接收并用私钥解开,从而完成整个加解密的通讯过程。那接下来我们就来模拟这样一个通讯过程

首先,我们需要把自己先扮演成CA机构,根据非对称加密的概念,我们需要有一对密钥,对应一把公钥和一把私钥,私钥放在自己身边,公钥提供出去,这边需要注意的是不能把他看成是服务端,CA机构是在客户端和服务端两者之间的一个存在,这边理解了后,我们先来创建一把私钥,可以使用openssl来生成

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl genrsa -out rootca.key 4096
Generating RSA private key, 4096 bit long modulus
................................................................++
...........++
e is 65537 (0x10001)

这样我们就生成了rootca.key的私钥文件,这个私钥是必须要保护好的,不能泄漏,然后我们来生成公钥,这边我们不会直接生成一把公钥对外开放,而是用上面提到的证书,为什么不直接用公钥呢?其实上面已经提到了,因为公钥私钥随便谁都可以生成出来,所以更重要的是要让客户端可以确认到这把公钥是否是受信任的,如果是受信任的才会使用这把公钥去和服务端交互,所以现在来生成一个带公钥的证书,我们可以叫他根证书

生成req请求文件,req请求文件用来生成证书的时候使用,其中包含了一些重要的信息,如证书所有者的一些信息等

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/rootCrt
$ openssl req -new -out rootca.csr -key rootca.key
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:sz
Locality Name (eg, city) []:sz
Organization Name (eg, company) [Internet Widgits Pty Ltd]:dobefa
Organizational Unit Name (eg, section) []:it
Common Name (e.g. server FQDN or YOUR name) []:karl
Email Address []:a.karl.com
string is too long, it needs to be less than  64 bytes long
Email Address []:a.karl.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:82468246
An optional company name []:dd

接着我们通过csr和key来生成根证书,会使用到x509工具,这样生成会比较便捷,不会依赖太多的openssl的知识

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl x509 -req -in rootca.csr -out rootca.crt -signkey rootca.key -days 36500
Signature ok
subject=/C=cn/ST=sz/L=sz/O=dobefa/OU=it/CN=karl/emailAddress=a.karl.com
Getting Private key

生成出rootca.crt,这个证书就是CA机构会预先在客户端中的受信任列表中埋下的根证书,其中包括了证书的所有者信息和公钥信息,有了这些信息,客户端就能通过这些信息来验证服务端返回的CA证书的合法性了

然后我们CA机构就可以开张营业了,CA机构会先把自己的证书让客户端放到其受信任的证书列表里,这边的客户端可以是Android系统,可以是Android的APP,也可以是Windows系统,也或者是Windows上的一个浏览器。我们这边先以Windows为例,把我们的CA证书植入进Windows的受信任列表中去,首先打开mmc

在这里插入图片描述

添加删除管理单元

在这里插入图片描述

选证书,添加

在这里插入图片描述

选计算机账户

在这里插入图片描述

本地计算机

在这里插入图片描述

完成后,就可以在列表中看到受信任的证书列表了

在这里插入图片描述

找到刚刚生成的ca根证书

在这里插入图片描述

安装证书,加入受信任列表

在这里插入图片描述

刷新刚刚的证书列表,就可以看到我们刚刚的证书

在这里插入图片描述

完成后,我们的CA机构就可以给别人颁发证书了,当然这边也是给我们自己颁发咯

我们来创建server密钥

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl genrsa -out server.key 4096
Generating RSA private key, 4096 bit long modulus
.........................................................................................................................++
.................................................................................................................................................................................++
e is 65537 (0x10001)

创建请求文件

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:js
Locality Name (eg, city) []:sz
Organization Name (eg, company) [Internet Widgits Pty Ltd]:dobefa
Organizational Unit Name (eg, section) []:it
Common Name (e.g. server FQDN or YOUR name) []:karl server
Email Address []:test.server.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:82468246
An optional company name []:server

使用根证书签发证书

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl x509 -req -in server.csr -CA rootca.crt -CAkey rootca.key -CAcreateserial -out server.crt -days 36500
Signature ok
subject=/C=cn/ST=js/L=sz/O=dobefa/OU=it/CN=karl server/emailAddress=test.server.com
Getting CA Private Key

做完这些步骤我们得到了一个server.crt,这个就是我们服务器的CA证书啦,这个服务端的CA证书是通过CA机构的私钥和CA根证书进行签名得到的,这样做会形成一个证书关联,这样我们就知道了这个服务器证书是出自哪个CA机构的哪张证书的了,我们可以查看下百度的证书会比较清楚,google浏览器为例

在这里插入图片描述

在这里插入图片描述

这个证书有三层的结构,根证书是GlobalSign的根证书,这是一个知名的CA机构,中间证书是GlobalSign使用根证书所生成出来的二级证书,而子证书就是GlobalSign颁发给baidu的CA证书了,大多数的CA证书都是通过二级CA来签发的,如果要实现这种结构的证书签署,会需要额外的一些配置来实现,所以我们这边暂不考虑这种做法,我们这边直接使用根CA进行签发,效果是一样的,这篇文章主要为了学习如何自签一个证书并完成https的交互过程,所以对证书签发感兴趣的同学可以学习更多关于openssl的知识。

接着,我们现在可以来试一下这个证书了,我们用go写一个非常简单的https服务器

package main

import (
	_ "github.com/icattlecoder/godaemon"
	"net/http"

	"github.com/gin-gonic/gin"
)

func setupRouter() *gin.Engine {
	// Disable Console Color
	// gin.DisableConsoleColor()
	r := gin.Default()

	// Ping test
	r.GET("/ping", func(c *gin.Context) {
		c.String(http.StatusOK, "pong")
	})

	return r
}

func main() {
	r := setupRouter()
	// Listen and Server in 0.0.0.0:8080
	r.RunTLS(":8081", "C:\\Users\\Administrator\\Desktop\\crt\\crtDemo\\server.crt", 
		"C:\\Users\\Administrator\\Desktop\\crt\\crtDemo\\server.key")
}

上面我们监听了本地8081端口,并且配置了/ping的接口,这个go程序启动后,访问https://ip地址:8081/ping就会返回pong的text,就这么简单,另外,为了能让这个程序常驻在后台,使用了"github.com/icattlecoder/godaemon"这个库,我们来启动他,在cmd中执行

go run main.go -d=true

然后在浏览器试试访问https://ip地址:8081/ping接口

在这里插入图片描述

啊,报警告了,这说明我们的证书有问题,不过我们已经将根证书埋入我们的系统信任列表中了啊,根据之前的理论,客户端拿着服务端带来的CA证书在本地受信任的CA证书列表中查找,并对比其公钥是否一致,一致则信任,不是吗?我们查看下server证书详细信息,省略部分不关注数据

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl x509 -in rootca.crt -noout -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            d9:a5:8c:82:6e:f7:a3:a1
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=cn, ST=sz, L=sz, O=dobefa, OU=it, CN=karl/emailAddress=a.karl.com
        Validity
            Not Before: Jan 28 07:46:36 2022 GMT
            Not After : Jan  4 07:46:36 2122 GMT
        Subject: C=cn, ST=sz, L=sz, O=dobefa, OU=it, CN=karl/emailAddress=a.karl.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    .......
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         ......

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl x509 -in server.crt -noout -text
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            fe:52:f8:e2:bf:78:1d:60
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=cn, ST=sz, L=sz, O=dobefa, OU=it, CN=karl/emailAddress=a.karl.com
        Validity
            Not Before: Jan 29 09:35:55 2022 GMT
            Not After : Jan  5 09:35:55 2122 GMT
        Subject: C=cn, ST=js, L=sz, O=dobefa, OU=it, CN=karl server/emailAddress=test.server.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    .......
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         .......

可以看到上面的server.crt证书的Issuer为rootca,是一致的

再来查看下rootca证书公钥和server证书的公钥

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/rootCrt
$ openssl x509 -in root2.crt -pubkey
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHRS1rCHo/DeXWQHvxHclhAkBT
as6VVbVFzf/tVjNHUsabKVnW6P+/ASQj+AoGgX+cjvX+6V44NcavJw8juokFrJki
MOZvt8wiY/kjsvMAZ8d1xTYYw0huUjMftFjemKJq7y6QFKrz+nqsJrsj1ThfFpfI
S3CAvnFMr9JtF+Uu8QIDAQAB
-----END PUBLIC KEY-----
................

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/rootCrt
$ openssl x509 -in root3.crt -pubkey
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHRS1rCHo/DeXWQHvxHclhAkBT
as6VVbVFzf/tVjNHUsabKVnW6P+/ASQj+AoGgX+cjvX+6V44NcavJw8juokFrJki
MOZvt8wiY/kjsvMAZ8d1xTYYw0huUjMftFjemKJq7y6QFKrz+nqsJrsj1ThfFpfI
S3CAvnFMr9JtF+Uu8QIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
................

发现也是一样的,那么还有哪边会有问题呢,我们看了google的提示信息,然后不妨看看百度的证书

在这里插入图片描述

这边有个重要的信息,即使用者可选名称,里面配置了好多DNS Name,还有通配符,而我们的证书是没有的,这就是关键了,其他的参数没有暂时还不影响我们的证书,所以我们来看看如何添加这个到我们的证书中

这个字段我们查到其对应的是“Subject Alternative Name”这个扩展字段,还记得我们在签发服务器证书的时候,使用的x509模块,该模块支持-extensions和-extfile来配置一个扩展字段,我们先建立一个配置文件ssl.cnf文件,内容如下

[ req_ext ]
subjectAltName = @alt_names

[alt_names]
IP.1    = 10.0.10.22
#DNS.1   = your-website.dev
#DNS.2   = another-website.dev

因为我们是使用的IP访问的,所以我们添加了一个IP.1 = 10.0.10.22的alt name

然后执行签发命令,带上配置文件

Administrator@PC-20210427XPHC MINGW64 ~/Desktop/crt/crtDemo
$ openssl x509 -req -in server.csr -CA rootca.crt -CAkey rootca.key -CAcreateserial -out server.crt -days 36500 -extensions req_ext -extfile ssl.cnf
Signature ok
subject=/C=cn/ST=js/L=sz/O=dobefa/OU=it/CN=karl server/emailAddress=test.server.com
Getting CA Private Key

确认一下我们的新的证书

$ openssl x509 -in server.crt -noout -text                                      Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            fe:52:f8:e2:bf:78:1d:61
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=cn, ST=sz, L=sz, O=dobefa, OU=it, CN=karl/emailAddress=a.karl.com
        Validity
            Not Before: Jan 30 03:27:04 2022 GMT
            Not After : Jan  6 03:27:04 2122 GMT
        Subject: C=cn, ST=js, L=sz, O=dobefa, OU=it, CN=karl server/emailAddress=test.server.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    .........
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Alternative Name:
                IP Address:10.0.10.22
    Signature Algorithm: sha256WithRSAEncryption
         ....................

可以看到X509v3 extensions: X509v3 Subject Alternative Name: IP Address:10.0.10.22已经配置到证书里面了,我们部署到go服务上,再来访问下浏览器试试吧

使用

taskkill /f /t /im main.exe

来关闭服务器进程,然后重新启动go服务,访问接口

在这里插入图片描述

这样就成功了,我们的证书已经被浏览器信任了。

  • 13
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卡卡爾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值