首页 > 其他分享 >https 服务示例 go-gin框架 支持ssl/tls,

https 服务示例 go-gin框架 支持ssl/tls,

时间:2024-09-03 15:37:36浏览次数:12  
标签:tls 证书 ca req 示例 server ssl key 服务端

本文为演示采用自签名证书

一.生成证书

通过openssl工具生成证书

1.1 安装openssl

macos通过brew安装

brew install openssl

1.2 生成跟证书私钥

openssl genrsa -out ca.key 4096

1.3 准备配置文件

vim ca.conf

内容如下

    [ req ]
    default_bits       = 4096
    distinguished_name = req_distinguished_name
     
    [ req_distinguished_name ]
    countryName                 = Country Name (2 letter code)
    countryName_default         = CN
    stateOrProvinceName         = State or Province Name (full name)
    stateOrProvinceName_default = JiangSu
    localityName                = Locality Name (eg, city)
    localityName_default        = NanJing
    organizationName            = Organization Name (eg, company)
    organizationName_default    = Sheld
    commonName                  = Common Name (e.g. server FQDN or YOUR name)
    commonName_max              = 64
    commonName_default          = Ted CA Test

生成根证书签发申请文件(csr文件)

openssl req -new -sha256 -out ca.csr -key ca.key -config ca.conf

该命令含义如下:

req——执行证书签发命令

-new——新证书签发请求

-key——指定私钥路径

-out——输出的csr文件的路径

1.4 自签发根证书(cer文件)

openssl x509 -req -days 3650 -in ca.csr -signkey ca.key -out ca.crt

该命令的含义如下:

x509——生成x509格式证书

-req——输入csr文件

-days——证书的有效期(天)

-signkey——签发证书的私钥

-in——要输入的csr文件

-out——输出的cer证书文件

1.5 生成服务端私钥

openssl genrsa -out server.key 2048

1.6 准备配置文件,得到server.conf

vim server.conf

内容如下

    [ req ]
    default_bits       = 2048
    distinguished_name = req_distinguished_name
    req_extensions     = req_ext
     
    [ req_distinguished_name ]
    countryName                 = Country Name (2 letter code)
    countryName_default         = CN
    stateOrProvinceName         = State or Province Name (full name)
    stateOrProvinceName_default = JiangSu
    localityName                = Locality Name (eg, city)
    localityName_default        = NanJing
    organizationName            = Organization Name (eg, company)
    organizationName_default    = Sheld
    commonName                  = Common Name (e.g. server FQDN or YOUR name)
    commonName_max              = 64
    commonName_default          = server.com
     
    [ req_ext ]
    subjectAltName = @alt_names
     
    [alt_names]
    DNS.1   = server.com

生成服务端证书申请文件

openssl req -new -sha256 -out server.csr -key server.key -config server.conf

参考1.3输入服务端证书信息

1.7 用CA证书签发服务端证书

openssl x509 -req -days 3650 -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt -extensions req_ext -extfile server.conf

这里有必要解释一下这几个参数:

-CA——指定CA证书的路径

-CAkey——指定CA证书的私钥路径

-CAserial——指定证书序列号文件的路径

-CAcreateserial——表示创建证书序列号文件(即上方提到的serial文件),创建的序列号文件默认名称为-CA,指定的证书名称后加上.srl后缀

1.8 生成客户端私钥

openssl genrsa -out client.key 2048

1.9 准备配置文件,得到client.conf

vim client.conf

内容如下

    [ req ]
    default_bits       = 2048
    distinguished_name = req_distinguished_name
    req_extensions     = req_ext
     
    [ req_distinguished_name ]
    countryName                 = Country Name (2 letter code)
    countryName_default         = CN
    stateOrProvinceName         = State or Province Name (full name)
    stateOrProvinceName_default = HeNan
    localityName                = Locality Name (eg, city)
    localityName_default        = AnYang
    organizationName            = Organization Name (eg, company)
    organizationName_default    = Sheld_client
    commonName                  = Common Name (e.g. server FQDN or YOUR name)
    commonName_max              = 64
    commonName_default          = server.com
     
    [ req_ext ]
    subjectAltName = @alt_names
     
    [alt_names]
    DNS.1   = server.com
    DNS.2    = localhost

生成客户端证书申请文件

openssl req -new -sha256 -out client.csr -key client.key -config client.conf

1.10 用跟证书签发客户端证书

openssl x509 -req -days 3650 -CA ca.crt -CAkey ca.key -CAserial ca.srl -in client.csr -out client.crt -extensions req_ext -extfile client.conf

需要注意的是,上方签发服务端证书时已经使用-CAcreateserial生成过ca.srl文件,因此这里不需要带上这个参数了。

二. gin框架实现https,服务端不需要验证客户端证书的示例
2.1 项目引入gin框架

go get -u github.com/gin-gonic/gin

2.2 服务端代码

   

package main
     
    import (
        "github.com/gin-gonic/gin"
        "net/http"
    )
     
    func main() {
        router := gin.New()
     
        router.GET("/test", func(c *gin.Context) {
            c.JSON(200, gin.H{
                "message": "success",
            })
        })
     
        // 可以直接用
        //router.RunTLS("0.0.0.0:10679", "./certs/server.cer", "./certs/server.key")
        server := &http.Server{Addr: "0.0.0.0:10679", Handler: router}
        _ = server.ListenAndServeTLS("./certs/server.cer", "./certs/server.key")
    }

 


2.3 安全提示

打开浏览器访问https://localhost:10679/test

因为浏览器并不信任证书的颁发机构,浏览器会有安全提示,当然可以点高级直接强行访问页面,同样可以返回结果,很多文章也是到这里就结束了。强迫症的我还是要解决一下。

2.4 给浏览器添加自己生成的CA证书

本文选择firefox浏览器,因为设置可以轻松添加信任CA证书。chrome则是直接掉起系统的证书,没有找到友好的办法自己添加

我们把CA证书(1.4节生成的ca.csr)添加到firefox证书颁发机构中去,这样浏览器就信任我们自制的CA证书了。路径为:设置->隐私与安全->查看证书->导入

由于我们证书配置的common name是server.com,因此需要修改本地hosts文件,将下面文字添加到hosts文件中

127.0.0.1 server.com

再次访问https://server.com:10679/test不再阻止

三.实现服务器和客户端双端验证

3.1 服务端代码

 

    package main
     
    import (
        "crypto/tls"
        "crypto/x509"
        "fmt"
        "github.com/gin-gonic/gin"
        "io/ioutil"
        "log"
        "net"
        "net/http"
        "os"
        "os/signal"
        "syscall"
    )
     
    var (
        caCert     string = "./certs/ca.crt"
        serverCert string = "./certs/server.crt"
        serverKey  string = "./certs/server.key"
    )
     
    func main() {
        router := gin.New()
        router.Use(gin.Logger())
     
        router.GET("/test", func(c *gin.Context) {
            c.JSON(200, gin.H{
                "message": "success",
            })
        })
     
        // 客户端CA证书
        certPool := x509.NewCertPool()
        ca, err := os.ReadFile(caCert)
        if err != nil {
            fmt.Printf("load ca err: %s", err)
            return
        }
     
        if ok := certPool.AppendCertsFromPEM(ca); !ok {
            fmt.Printf("certpool append ca fail.")
            return
        }
     
        // 可以直接用注释的代码代替最后两行
        //router.RunTLS("0.0.0.0:10679", "./cert/server.cer", "./cert/server.key")
        server := &http.Server{
            Addr:    "server.com:10679",
            Handler: router,
            TLSConfig: &tls.Config{
                ClientAuth: tls.RequireAndVerifyClientCert,
                //这里一定要注意,服务端设置ClientCAs,用于服务端验证客户端证书,客户端设置RootCAs,用户客户端验证服务端证书。设置错误或者设置反了都会造成认证不通过。
                //RootCAs:    certPool,
                ClientCAs: certPool,
            },
        }
     
        _ = server.ListenAndServeTLS(serverCert, serverKey)
    }

 



3.2 客户端代码

  

 package main
     
    import (
        "crypto/tls"
        "crypto/x509"
        "fmt"
        "io/ioutil"
        "log"
        "net/http"
        "os"
    )
     
    func main() {
        pool := x509.NewCertPool()
        caCrt, err := os.ReadFile("./certs/ca.crt")
        if err != nil {
            log.Fatal("read ca.crt file error:", err.Error())
        }
        pool.AppendCertsFromPEM(caCrt)
        cliCrt, err := tls.LoadX509KeyPair("./certs/client.crt", "./certs/client.key")
        if err != nil {
            log.Fatalln("LoadX509KeyPair error:", err.Error())
        }
        tr := &http.Transport{
            TLSClientConfig: &tls.Config{
                //这里一定要注意,服务端设置ClientCAs,用于服务端验证客户端证书,客户端设置RootCAs,用户客户端验证服务端证书。设置错误或者设置反了都会造成认证不通过。
                RootCAs: pool,
                //ClientCAs:    pool,
                Certificates: []tls.Certificate{cliCrt},
            },
        }
        client := &http.Client{Transport: tr}
        resp, err := client.Get("https://server.com:10679/test")
        if err != nil {
            fmt.Printf("get failed. | err: %s\n", err)
            return
        }
        defer resp.Body.Close()
        body, err := ioutil.ReadAll(resp.Body)
        fmt.Println(string(body))
     
    }

 


四. 整理过程中遇到的bug

4.1 tls: failed to verify certificate: x509: “server.com” certificate is not standards compliant

remote error: tls: bad certificate

这两个报错可能就是客户端或服务端设置参数ClientCAs、RootCAs错误有关。

服务端设置ClientCAs,里面保存客户端的CA证书Pool,用于服务端验证客户端证书。

客户端设置RootCAs,里面保存服务端的CA证书Pool,用户客户端验证服务端证书。

设置错误或者设置反了都会造成认证不通过。

这就属于知道就很简单解决,但找不到错误就很崩溃,本人因为这个小bug竟然熬了一夜,说多了都是泪啊啊啊啊。。。

4.2 use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0

这个报错原因是生成证书没有开启SAN扩展,go 1.15 版本开始废弃 CommonName,因此推荐使用 SAN 证书。 这就是1.6、1.9两节配置文件最下面做的事情。重新把证书生成一下。当然,自己生成的证书可以随便改,如果线上证书出现这种情况,我看有的说设置下环境变量GODEBUG 为 x509ignoreCN=0,不过我测试没有效果

这个问题的解决要感谢下面这个博主,我是看了这个帖子解决的问题。

https://blog.csdn.net/weixin_40280629/article/details/113563351

4.3 安全提示

参考2.3解决办法

4.4 证书commonName

这个字段是比较重要的,不要随便配置。服务端、客户端证书认证都会验证host name是否与其一致,不一致会造成认证失败。这也是为什么要修改hosts并用server.com来访问
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/chen_peng7/article/details/128978575

标签:tls,证书,ca,req,示例,server,ssl,key,服务端
From: https://www.cnblogs.com/a208606/p/18394710

相关文章

  • 配置 expect 免交互自动化脚本 2个示例
    文章目录示例1:实现密码输入错误的提示示例2:用免交互的方式给硬盘分区、格式化、挂载示例1:实现密码输入错误的提示在expect脚本中,可以通过捕捉密码错误的输出信息来提示用户。比如:expect{"password"{send"$password\r"}"Permissiondenied"{send_......
  • vue使用echart示例
    <template><el-cardshadow="never"><template#header><divclass="flexjustify-between"><spanclass="text-sm">订单统计</span><div&g......
  • 25. shell当中的函数详解,管理函数,定义函数,交互式环境调用函数,查看删除函数,脚本中的函
    文章目录前言管理函数定义函数交互式环境调用函数查看函数删除函数脚本中的函数定义及使用函数使用函数文件环境函数示例总结友情链接前言函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独......
  • 32.全网最详细trap讲解,trap语法格式,信号和用途,最常用的信号,trap常用的命令,ctrl +
    文章目录语法详解trap格式信号和用途最常用的信号trap常用的命令示例ctrl+c示例信号屏蔽和恢复trap-示例debug示例exit示例return示例综合案例案例1案例2案例3总结友情链接信号捕捉trap,它用于捕获指定的信号并执行预定义的命令。比如,按Ctrl+C会使脚本终止执行,实际上系统发......
  • 【Certimate - 免费SSL证书自动申请、续期工具】开源 SSL 证书自动管理工具推荐
    CertimateCertimate是一个开源的SSL证书管理工具,具有以下特点:支持私有部署:部署方法简单,只需下载二进制文件并执行即可完成安装。数据安全:由于是私有部署,所有数据均存储在本地,不会保存在服务商的服务器上,确保数据的安全性。操作方便:通过简单的配置即可轻松申请SSL证......
  • 使用同步锁的代码示例1
    使用同步锁的代码示例packageorg.zyf.javabasic.thread.lock.opti;importjava.util.concurrent.locks.ReentrantLock;/***@program:zyfboot-javabasic*@description:使用了ReentrantLock来保护对共享资源(counter)的访问,确保同一时间只有一个线程可以对计数器......
  • 使用同步锁的代码示例26
    使用同步锁的代码示例packageorg.zyf.javabasic.thread.lock.opti;importjava.util.concurrent.locks.ReentrantLock;/***@program:zyfboot-javabasic*@description:使用了ReentrantLock来保护对共享资源(counter)的访问,确保同一时间只有一个线程可以对计数器......
  • 使用同步锁的代码示例30
    使用同步锁的代码示例packageorg.zyf.javabasic.thread.lock.opti;importjava.util.concurrent.locks.ReentrantLock;/***@program:zyfboot-javabasic*@description:使用了ReentrantLock来保护对共享资源(counter)的访问,确保同一时间只有一个线程可以对计数器......
  • 【路径规划】在二维环境中快速探索随机树和路径规划的示例
    摘要本文介绍了快速探索随机树(Rapidly-exploringRandomTree,RRT)算法在二维环境中的路径规划应用。RRT是一种随机采样算法,能够快速构建从起点到目标点的路径,特别适用于复杂环境中的机器人路径规划。通过在随机方向上扩展树结构,RRT算法能够高效避开障碍物并找到一条可行路径......
  • 在Java中23种设计模式,分类以及代码示例
    在Java中23种设计模式,分类以及代码示例在Java中,设计模式可以分为23种,以三个不同的分类进行划分。1.创建型模式(CreationalPatterns):单例模式(Singleton)原型模式(Prototype)工厂方法模式(FactoryMethod)抽象工厂模式(AbstractFactory)建造者模式(Builder)2.结构型模式(Structura......