TLS-Golang实现

转载:

前言

在进行项目总结的时候,领导提出有关数据安全的问题。总结会议过后,自己查阅了一下资料,发现基于CA的TLS证书认证方案是一个很好的选择,虽然项目本身也有关于数据安全的处理,但是从远不及TLS的处理方式。

本文只介绍tls的开发,采用go语言,不会涉及到太多专业的词语。


制作自签名证书

初始目录如下:





CA

为了保证证书的可靠性和有效性,在这里可引入 CA 颁发的根证书的概念。CA就是专门用自己的私钥给别人进行签名的单位或者机构,其遵守 X.509 标准,即无论是客户端还是服务端都是使用CA来签发证书。

根证书

根证书(root certificate)是属于根证书颁发机构(CA)的公钥证书。我们可以通过验证 CA 的签名从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书(客户端、服务端)。

它包含了公钥和密钥。

CA公钥

进入cert目录

openssl genrsa -out ca.key 2048

  • openssl genrsa:生成RSA私钥,命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认512

CA秘钥(证书)

openssl req -new -x509 -days 365 -key ca.key -out ca.pem

  • -x509:证书文件格式为x509,目前TLS默认只支持这种格式的证书
  • -days 365:证书有效期1年
  • -out ca.pem:生成的私钥保存到ca.pem

要填写的信息:

Country Name (2 letter code) [XX]: State or Province Name (full name) []: Locality Name (eg, city) [Default City]: Organization Name (eg, company) [Default Company Ltd]: Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:ca.com Email Address []:
  • 生成的过程中会要求填一些信息,除了Common Name要取一个容易区分的名字之外,其它都可以随便填写,我们在这里将它填为ca.com.

目录





服务器证书相关

服务器key

# openssl genrsa -out server.key 2048
或者
openssl ecparam -genkey -name secp384r1 -out server.key
  • openssl genrsa:生成RSA私钥,命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认512
  • openssl ecparam:生成ECC私钥,命令为椭圆曲线密钥参数生成及操作,本文中ECC曲线选择的是secp384r1

生成 CSR(证书申请文件)

CSR 是Cerificate Signing Request 的英文缩写,为证书申请文件,在服务器私钥的基础上加上一些申请人的属性信息,比如我是谁,来自哪里,名字叫什么,证书适用于什么场景等的信息,然后带上进行的签名,发给CA(私下安全的方式发送),带上自己签名的目的是为了防止别人篡改文件。

openssl req -new -key server.key -out server.csr

要填写的信息:

Country Name (2 letter code) [AU]: State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]: Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:domain.com Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:123456 An optional company name []:
  • 生成的过程中会要求填一些信息,除了Common Name要取一个容易区分的名字之外,其它都可以随便填写,我们在这里将它填为domain.com;
  • 密码也是建议填写;
  • 注意和ca证书的不同。

基于 CA 签发

使用CA的公钥对申请文件进行签名

openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
  • -sha256:生成的证书里面使用sha256作为摘要算法
  • 由于需要往生成的证书里写入签名者的信息,所以这里需要ca.pem,因为只有这里有CA的描述信息,ca.key里面只有公钥的信息。

目录

grpc-tls/ ├── configs │   ├── cert # 存放证书相关的目录 │       ├── ca.key │       └── ca.pem │       ├── server.csr │       └── server.key │       └── server.pem ├── cmd

客户端证书相关

此生成的证书可用于浏览器、java、tomcat、golang等。

客户端key

openssl ecparam -genkey -name secp384r1 -out client.key

生成CSR(证书申请书)

openssl req -new -key client.key -out client.csr

要填写的信息:

  • Common Name要取一个容易区分的名字之外,填为domain.com,和服务器的CSR保持一致;
  • 密码也是建议填写;
  • 注意和ca证书的不同。

基于CA签发

openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem

生成客户端p12格式根证书

该证书用于导入浏览器使用。

openssl pkcs12 -export -clcerts -in client.pem -inkey client.key -out client.p12

目录

grpc-tls/
├── configs
│   ├── cert # 存放证书相关的目录
│       ├── ca.key
│       └── ca.pem # 导入浏览器使用
│       ├── server.csr
│       └── server.key
│       └── server.pem
│       ├── client.csr
│       └── client.key
│       └── client.pem
│       └── client.p12 # 导入浏览器使用
├── cmd

证书如何验证

下面以浏览器为例,说明证书的验证过程:

  • 在TLS握手的过程中,浏览器得到了网站的证书(.p12)
  • 打开证书,查看是哪个CA签名的这个证书(.p12)
  • 在自己信任的CA库中,找相应CA的证书(ca.pem),
  • 用CA证书里面的公钥解密网站证书上的签名,取出网站证书的校验码(指纹),然后用CA证书中摘要算法(比如sha256)算出出网站证书的校验码,如果校验码和签名中的校验码对的上,说明这个证书是合法的,且没被人篡改过
  • 读出里面的CN,对于网站的证书,里面一般包含的是域名
  • 检查里面的域名和自己访问网站的域名对不对的上,对的上的话,就说明这个证书确实是颁发给这个网站的
  • 到此为止检查通过

如果浏览器发现证书有问题,一般是证书里面的签名者不是浏览器认为值得信任的CA,浏览器就会给出警告页面,这时候需要谨慎,有可能证书被掉包了。如访问12306网站,由于12306的证书是自己签的名,并且浏览器不认为12306是受信的CA,所以就会给警告,但是一旦你把12306的根证书安装到了你的浏览器中,那么下次就不会警告了,因为你配置了浏览器让它相信12306是一个受信的CA。


在浏览器中导入证书

导入证书

  • 详细步骤百度即可….
  • 个人导入client.p12证书
  • 受信任的根证书颁发机构导入ca.pem证书

修改域名

ca.pem这个证书是发给domain.com的,而不是127.0.0.1,所以在C:\Windows\System32\drivers\etc\hosts添加一记录:

测试完成之后记得手动将127.0.0.1 domain.comC:\Windows\System32\drivers\etc\hosts里面删掉。


golang服务端

目录

grpc-tls/
├── configs
│   ├── cert # 存放证书相关的目录
│       ├── ca.key
│       └── ca.pem # 导入浏览器使用
│       ├── server.csr
│       └── server.key
│       └── server.pem
│       ├── client.csr
│       └── client.key
│       └── client.pem
│       └── client.p12 # 导入浏览器使用
├── cmd
│   ├── main.go

main.go

package main

import (
    "crypto/tls"
    "crypto/x509"
    "github.com/gin-gonic/gin"
    "io/ioutil"
    "log"
    "net/http"
    "time"
)

func main() {
    router := gin.Default()
    router.GET("/test", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "test",
        })
    })

    // 启动https方式访问
    cert, err := tls.LoadX509KeyPair("./configs/cert/server.pem", "./configs/cert/server.key")
    if err != nil {
        log.Fatalf("tls.LoadX509KeyPair err: %v", err)
    }
    certPool := x509.NewCertPool()
    ca, err := ioutil.ReadFile("./configs/cert/ca.pem")
    if err != nil {
        log.Fatalf("ioutil.ReadFile err: %v", err)
    }
    if ok := certPool.AppendCertsFromPEM(ca); !ok {
        log.Fatalf("certPool.AppendCertsFromPEM err")
    }
    ReadTimeout := time.Duration(60) * time.Second
    WriteTimeout := time.Duration(60) * time.Second

    s := &http.Server{
        Addr:          ":8090",
        Handler:        router,
        ReadTimeout:    ReadTimeout,
        WriteTimeout:   WriteTimeout,
        MaxHeaderBytes: 1 << 20,
        TLSConfig:&tls.Config{
            Certificates: []tls.Certificate{cert},
            MinVersion: tls.VersionTLS12,
            ClientAuth:   tls.RequireAndVerifyClientCert,
            ClientCAs:    certPool,
        },
    }

    s.ListenAndServeTLS("./configs/cert/server.pem","./configs/cert/server.key")
}

测试

在浏览器输入https://domain.com:8090/test

https://img2018.cnblogs.com/blog/1481607/201907/1481607-20190718144205177-1562071036.png

参考

SSL/TLS及证书概述

带入gRPC:TLS 证书认证

GoCN每日新闻(2019-07-20)

1. Go程序内存分配优化 https://blog.twitch.tv/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap-26c2462549a2

2. Go代码最常见的10个错误 https://itnext.io/the-top-10-most-common-mistakes-ive-seen-in-go-projects-4b79d4f6cd65

3. Golang中interface底层分析 https://juejin.im/post/5d31884af265da1baa1eae79

4. Go语言入门[翻译] https://juejin.im/post/5d316b69f265da1bb9701720

5. Go程序平滑重启 https://github.com/cloudflare/tableflip

编辑: samurai

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3620

GoCN每日新闻(2019-07-19)

1. Golang 中的垃圾回收(三)https://www.ardanlabs.com/blog/2019/07/garbage-collection-in-go-part3-gcpacing.html

2. golang中defer的执行过程是怎样的?https://juejin.im/post/5d303506f265da1b925412b9

3. Vugu:Go + WebAssembly的现代UI库 https://www.vugu.org/

4. 针对NAS设备的Go语言勒索软件已被破解 https://www.secrss.com/articles/12159

5. TLS示例开发-golang版本 https://www.cnblogs.com/dust90/p/11207219.html

编辑: 何小云

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3619

GoCN每日新闻(2019-07-18)

1.Go 并发编程范式 https://taigacute.github.io/2019/07/17/Go-%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E8%8C%83%E5%BC%8F/

2. Golang Modules学习  http://www.huamo.online/2019/07/08/Golang-Modules%E5%AD%A6%E4%B9%A0/

3. Go Channel  https://taigacute.github.io/2019/07/14/Go-Channel/

4. Go的Sync包  https://taigacute.github.io/2019/07/12/Go%E7%9A%84Sync%E5%8C%85/

5. 深入研究goroutine栈  http://www.huamo.online/2019/06/25/%E6%B7%B1%E5%85%A5%E7%A0%94%E7%A9%B6goroutine%E6%A0%88/

编辑: 崔广章

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3616

GoCN每日新闻(2019-07-17)

1. Go try 提议被拒 https://github.com/golang/go/issues/32437#issuecomment-512035919

2. Go 编程:那些隐晦的操作符 https://www.gitdig.com/go-operators/

3. [译] 使用 Gomobile 和 Gopherjs 的动态二维码数据传输 https://juejin.im/post/5d2bfccef265da1bb77699e8

4. Go中句法糖的成本 https://medium.com/@asilvr/the-cost-of-syntactic-sugar-in-go-5aa9dc307fe0

5. Go编写的高性能、自我托管的通讯及邮件列表管理器 https://github.com/knadh/listmonk

编辑: 周云轩

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3614

GoCN每日新闻(2019-07-16)

1. Go 并发算法:http://www.golangprograms.com/go-language/concurrency.html

2. Go websocket 框架:https://github.com/kataras/neffos

3. Go 医学图像解析器: https://github.com/suyashkumar/dicom

4. 使用服务网格简化微服务安全性问题:https://www.cncf.io/blog/2019/04/25/simplifying-microservices-security-with-a-service-mesh/

5. MongoDB 4.2 特性预览:https://www.mongodb.com/blog/post/mongodb-42-previewed-at-mongodb-world 

招聘信息:

* [北京-微博招聘]招聘golang工程师-广告平台: https://gocn.vip/question/3608

编辑: 薛锦

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3612

GoCN每日新闻(2019-07-15)

1. Go 逃逸分析 https://github.com/WilburXu/blog/blob/master/Golang/Go%20%E9%80%83%E9%80%B8%E5%88%86%E6%9E%90.md

2. Go 编程:图解反射 https://www.gitdig.com/go-reflect

3. Go Micro Register 源码分析 https://segmentfault.com/a/1190000019758939

4. 文件分享中继服务器 https://github.com/schollz/hostyoself

5. 为微服务开发者打造的开发工具 https://github.com/eko/monday

编辑: 宋佳洋

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3607

GoCN每日新闻(2019-07-14)

1. 如何使用 try https://faiface.github.io/post/how-to-use-try/

2. Go程序是怎样跑起来的 https://mp.weixin.qq.com/s/Rewl0DKnq6CY53m5D3G2qw

3. 可编程的HTTP/S代理工具martian https://github.com/google/martian

4. cockroachdb出品的errors库 https://github.com/cockroachdb/errors

5. Go可视化调用工具gocyto https://github.com/protolambda/gocyto

编辑: lwhile

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3602

GoCN每日新闻(2019-07-13)

GoCN每日新闻(2019-07-13)

1. Go 1.13 中 Modules 的标准特性 https://mp.weixin.qq.com/s/SGGV3tWEg5AAJ7I_FcK0cg

2. Golang 并发编程与定时器 https://draveness.me/golang/concurrency/golang-timer.html

3. Golang语言defer特性详解 https://www.jianshu.com/p/57acdbc8b30a

4. Golang time.After内存泄露问题分析 https://www.cnblogs.com/luoming1224/p/11174927.html

5. Go 编程:图解反射 https://www.gitdig.com/go-reflect

编辑: 马怀博 

订阅新闻: http://tinyletter.com/gocn

GoCN归档: https://gocn.vip/question/3599

GoCN每日新闻(2019-07-12)

1. Golang 大杀器之跟踪剖析 trace https://juejin.im/post/5d27400151882530af139a85

2. Go语言的微服务开发工具 https://www.bugsnag.com/blog/microservice-developer-tools-for-gophers

3. [译]思考实践:用Go实现Flutter https://juejin.im/post/5d215b8df265da1b7b31ac8f

4. Goch:Go语言编写的在线聊天服务 https://github.com/ribice/goch

5. orbital:一个端对端测试框架 https://github.com/segmentio/orbital

编辑: Razil

订阅新闻: http://tinyletter.com/gocn

GoCN归档:https://gocn.vip/question/3590