当前位置: 首页 > news >正文

go语言实现http双向认证

1准备客户端、服务端、根证书

├── client

   ├── client.crt

   ├── client.csr

   ├── client.key

   └── tls.cnf

├── root

   ├── root.crt

   ├── root.key

   ├── root.srl

   └── tls.cnf

└── server

    ├── server.crt

    ├── server.csr

    ├── server.key

└── tls.cnf

# root配置

>> cat tls.cnf 

[ req ]

default_bits = 2048

prompt = no

default_md = sha256

req_extensions = v3_ext

distinguished_name = dn

 

[ dn ]

C  = CN

ST = Jiangsu

L  = NJ

O  = ROOT

CN =localhost # 通用名(Common Name):证书的主域名

 

 

[ req_ext ] # 备用名称(SAN),现代TLS强制要求,定义证书有效的所有域名

 

subjectAltName = @alt_names

 

[ alt_names ]

DNS.1 = localhost

 

[ v3_ext ]

basicConstraints=CA:FALSE

keyUsage=keyEncipherment,dataEncipherment

extendedKeyUsage=serverAuth,clientAuth

subjectAltName=@alt_names

# server配置

>> cat tls.cnf 

[ req ]

default_bits = 2048

prompt = no

default_md = sha256

req_extensions = v3_ext

distinguished_name = dn

 

[ dn ]

C  = CN

ST = Jiangsu

L  = NJ

O  = SERVER

CN = com.test.server 通用名(Common Name):证书的主域名

 

 

[ req_ext ] # 备用名称(SAN),现代TLS强制要求,定义证书有效的所有域名

 

subjectAltName = @alt_names

 

[ alt_names ]

DNS.1 = localhost

DNS.2 = com.test.server

 

[ v3_ext ]

basicConstraints=CA:FALSE

keyUsage=keyEncipherment,dataEncipherment

extendedKeyUsage=serverAuth,clientAuth

subjectAltName=@alt_names

 

 

# client配置

 

>> cat tls.cnf 

 

[ req ]

 

default_bits = 2048

 

prompt = no

 

default_md = sha256

 

req_extensions = v3_ext

 

distinguished_name = dn

 

 

 

[ dn ]

 

C  = CN

 

ST = Jiangsu

 

L  = NJ

 

O  = CLIENT

 

CN =com.test.client # 通用名(Common Name):证书的主域名

 

 

 

 

 

[ req_ext ] # 备用名称(SAN),现代TLS强制要求,定义证书有效的所有域名

 

 

 

subjectAltName = @alt_names

 

 

 

[ alt_names ]

 

DNS.1 = localhost

 

DNS.2 = com.test.client

 

 

 

[ v3_ext ]

 

basicConstraints=CA:FALSE

 

keyUsage=keyEncipherment,dataEncipherment

 

extendedKeyUsage=serverAuth,clientAuth

 

subjectAltName=@alt_names

 

 

1、生成根证书

 

openssl genrsa -out root.key 2048

 

openssl req -x509 -new -nodes -key root.key -subj "/CN=ROOT CA" -days 7300 -out root.crt

 

 

 

2、生成服务端证书

 

openssl genrsa -out server.key 2048

 

openssl req -new -key server.key -out server.csr -config tls.cnf

 

openssl x509 -req -in server.csr -CA root.crt -CAkey root.key \-CAcreateserial -out server.crt -days 3650 \-extensions v3_ext -extfile tls.cnf

 

 

 

3、生成客户端证书

 

openssl genrsa -out client.key 2048

 

openssl req -new -key client.key -out client.csr -config tls.cnf

 

openssl x509 -req -in client.csr -CA root.crt -CAkey root.key \-CAcreateserial -out client.crt -days 3650 \-extensions v3_ext -extfile tls.cnf

 

4、编写服务端代码

package mainimport ("crypto/tls""crypto/x509""encoding/json""fmt""io/ioutil""net/http""time""github.com/gorilla/mux"log "github.com/sirupsen/logrus"
)func main() {var (rootPath = "/root/app/root.crt"certPath = "/root/app/server.crt"keyPath  = "/root/app/server.key")certPool := x509.NewCertPool()rootCert, err := ioutil.ReadFile(rootPath)if err != nil {log.Fatalf("Failed to read CA certificate: %v", err)}if ok := certPool.AppendCertsFromPEM(rootCert); !ok {log.Fatal("Failed to append CA certificate")}cfg := &tls.Config{ClientAuth:         tls.RequireAndVerifyClientCert,InsecureSkipVerify: false,ClientCAs:          certPool,MinVersion:         tls.VersionTLS12,CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,},}cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {if len(verifiedChains) == 0 || len(verifiedChains[0]) == 0 {return fmt.Errorf("no certificate chain verified")}clientCert := verifiedChains[0][0]allowedDomains := []string{"com.test.client"}for _, dns := range clientCert.DNSNames {for _, allowed := range allowedDomains {if dns == allowed {return nil}}}return fmt.Errorf("certificate SAN not in allowed list")}r := mux.NewRouter()r.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {var resp = make(map[string]string)resp["status"] = "ok"resp["msg"] = "success"_ = json.NewEncoder(w).Encode(resp)}).Methods("GET")server := &http.Server{Addr:              ":" + "15000",Handler:           r,TLSConfig:         cfg,ReadHeaderTimeout: 30 * time.Second,}log.Info("listening on port " + "15000")err = server.ListenAndServeTLS(certPath, keyPath)if err != nil {log.Errorf("ListenAndServeTLS failed:%s", err.Error())}
}

  

5、编写客户端代码

package mainimport ("context""crypto/tls""crypto/x509""fmt""io"_ "io""io/ioutil""net/http"log "github.com/sirupsen/logrus"
)var (rootPath       = "/root/app/root.crt"clientCertPath = "/root/app/client.crt"clientKeyPath  = "/root/app/client.key"
)func createHttpClient() (*http.Client, error) {rootCert, err := ioutil.ReadFile(rootPath)if err != nil {log.Fatalf("Failed to read CA certificate: %v", err)}certPool := x509.NewCertPool()if ok := certPool.AppendCertsFromPEM(rootCert); !ok {log.Fatal("Failed to append CA certificate")}crtText, _ := ioutil.ReadFile(clientCertPath)keyText, _ := ioutil.ReadFile(clientKeyPath)certPair, _ := tls.X509KeyPair(crtText, keyText)transport := &http.Transport{TLSClientConfig: &tls.Config{RootCAs:            certPool,InsecureSkipVerify: false,Certificates:       []tls.Certificate{certPair},MinVersion:         tls.VersionTLS12,CipherSuites: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,},},}client := &http.Client{Transport: transport}return client, nil
}func main() {client, err := createHttpClient()if err != nil {log.Fatalln(err)}ctx := context.TODO()url := fmt.Sprintf("https://com.test.server:15000/test")req, err := http.NewRequestWithContext(ctx, "GET", url, nil)if err != nil {log.Fatalln(err)}req.Header.Set("Content-Type", "application/json")response, err := client.Do(req)if err != nil {log.Fatalln(err)}var v []byteif v, err = io.ReadAll(response.Body); err != nil {log.Fatalln(err)} else {fmt.Println(string(v))}}

使用:

生产环境上需要在服务端和客户端服务器上的/etc/hosts文件中配置对方的的ip到域名的映射。

    "context"
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io"
    _ "io"
    "io/ioutil"
    "net/http"

    log "github.com/sirupsen/logrus"
)

var (
    rootPath       = "/root/app/root.crt"
    clientCertPath = "/root/app/client.crt"
    clientKeyPath  = "/root/app/client.key"
)

func createHttpClient() (*http.Client, error) {
    rootCert, err := ioutil.ReadFile(rootPath)
    if err != nil {
       log.Fatalf("Failed to read CA certificate: %v", err)
    }
    certPool := x509.NewCertPool()
    if ok := certPool.AppendCertsFromPEM(rootCert); !ok {
       log.Fatal("Failed to append CA certificate")
    }

    crtText, _ := ioutil.ReadFile(clientCertPath)
    keyText, _ := ioutil.ReadFile(clientKeyPath)
    certPair, _ := tls.X509KeyPair(crtText, keyText)

    transport := &http.Transport{
       TLSClientConfig: &tls.Config{
          RootCAs:            certPool,
          InsecureSkipVerify: false,
          Certificates:       []tls.Certificate{certPair},
          MinVersion:         tls.VersionTLS12,
          CipherSuites: []uint16{
             tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
             tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
             tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
             tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
             tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
             tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
          },
       },
    }
    client := &http.Client{Transport: transport}
    return client, nil
}

func main() {
    client, err := createHttpClient()
    if err != nil {
       log.Fatalln(err)
    }

    ctx := context.TODO()
    url := fmt.Sprintf("https://com.test.server:15000/test")

    req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
    if err != nil {
       log.Fatalln(err)
    }
    req.Header.Set("Content-Type", "application/json")
    response, err := client.Do(req)
    if err != nil {
       log.Fatalln(err)
    }
    var v []byte
    if v, err = io.ReadAll(response.Body); err != nil {
       log.Fatalln(err)
    } else {
       fmt.Println(string(v))
    }

}

http://www.jsqmd.com/news/373271/

相关文章:

  • 微服务架构在 C++ 和 Python中的应用
  • 【JAVA 进阶】深入探索Spring AOP:从原理到实战 - 指南
  • 2026年河北环卫公司推荐:行业先锋综合评估报告发布 - 品牌推荐
  • AI4Science开源数据汇总
  • ML.NET 作为 .NET 生态的轻量级机器学习框架,在**异常检测**(Anomaly Detection)领域提供了几类高级算法,尤其适合工控机边缘部署
  • 2026年知名的项目综合管理,项目组合管理系统,项目集管理公司用户好评名录 - 品牌鉴赏师
  • 超越PCA:设计可扩展、可解释的现代降维算法组件
  • Java小白互联网大厂面试场景:从Spring Boot到微服务架构的问答解析
  • Teamcenter用户登录失败或模块访问被拒的深度原因分析与解决
  • 2026年河北环卫公司推荐榜单:覆盖多场景服务、90%客户满意率的五强权威认证 - 品牌推荐
  • Ubuntu 24.04 设置开机自动启动命令
  • AI写论文风向标!4个热门AI论文生成工具,写论文不再是烦恼!
  • AI写论文有妙招!4款AI论文生成工具,帮你快速搞定毕业论文!
  • 2026年河北环卫公司推荐榜单:覆盖城乡一体化、智慧化转型需求的五强权威认证 - 品牌推荐
  • 《P2513 [HAOI2009] 逆序对数列》
  • 微信Linux版QVD-2026-7687漏洞深度复现:点击即执行,漏洞原理、验证方法与防御指南
  • AI写论文的绝佳选择!4款AI论文写作神器,让论文创作事半功倍!
  • 英伟达红队重磅发布:AI Agent安全实践指南,筑牢执行层安全防线
  • 88 并发工具类综合应用
  • 86 线程安全问题排查
  • 小班不小众,提分更提效——七星教育领跑合肥初高中精细化辅导赛道 - 品牌企业推荐师(官方)
  • 致命零信任漏洞:CVE-2025-59287深度剖析——WSUS不安全反序列化如何沦为内网渗透突破口
  • 专业的液体磷肥供应商生产厂家 - 品牌企业推荐师(官方)
  • 87 ForkJoinPool框架深度剖析
  • 潜伏的IRC控制军团:SSHStalker僵尸网络技术解析与防御前瞻
  • 什么是赫布原理(Hebbian principle / Hebbs rule)?
  • Windows 记事本(CVE-2026-20841)漏洞深度剖析——点击即沦陷,远程代码执行风险逼近
  • 2026最新江西家政服务推荐:月嫂、育儿嫂、护理老人、住家保姆、不住家保姆优质服务商榜单 - 品牌企业推荐师(官方)
  • 表格设计:结构与美感并重
  • 护眼台灯哪个品牌技术可靠?2026年护眼台灯品牌推荐与排名,解决光谱与耐用性核心痛点 - 品牌推荐