[golang]使用mTLS双向加密认证http通信

这篇具有很好参考价值的文章主要介绍了[golang]使用mTLS双向加密认证http通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

假设一个场景,服务端部署在内网,客户端需要通过暴露在公网的nginx与服务端进行通信。为了避免在公网进行 http 明文通信造成的信息泄露,nginx与客户端之间的通信应当使用 https 协议,并且nginx也要验证客户端的身份,也就是mTLS双向加密认证通信。

这条通信链路有三个角色:服务端、Nginx、客户端。

  • 服务端部署在内网,与nginx使用http通信。
  • 客户端在公网,与nginx使用https通信,且双向加密认证。

[golang]使用mTLS双向加密认证http通信

服务端

服务端只使用http,所以这里用gin框架写个简单的示例,返回客户端一些基本的http信息,比如客户端IP、请求方法、host等。

package main

import (
	"log"
	"net/http"
	"time"

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

/* 中间件: 获取api处理时长 */
func midElapsed(c *gin.Context) {
	start := time.Now()
	c.Next()
	elapsed := time.Since(start)
	log.Printf("API: %s, elapsed: %s", c.Request.URL.Path, elapsed)
}

/* 处理 GET / 请求 */
func f1(c *gin.Context) {
	// 获取客户端IP
	clientIP := c.ClientIP()

	// 获取请求方法
	method := c.Request.Method

	// 获取协议
	proto := c.Request.Proto

	// 获取host
	host := c.Request.Host

	// 请求Path
	path := c.Request.URL.Path

	log.Printf("客户端IP: %s, 请求方法: %s, 协议: %s, host: %s, path: %s", clientIP, method, proto, host, path)

	// 获取请求头
	headers := c.Request.Header
	for hk, hv := range headers {
		log.Printf("header key: %s, value: %s", hk, hv)
	}

	// 获取名为"mycookie"的cookie
	var cookies []string
	cookie, err := c.Cookie("mycookie")
	if err != nil {
		log.Printf("get cookie [mycookie] error: %s", err)
	} else {
		log.Printf("get cookie [mycookie]: %s", cookie)
		cookies = append(cookies, cookie)
	}

	c.JSON(http.StatusOK, gin.H{
		"clientIP": clientIP,
		"method":   method,
		"proto":    proto,
		"host":     host,
		"headers":  headers,
		"cookies":  cookies,
		"path":     path,
	})
}

func main() {
	r := gin.Default()
	r.Use(midElapsed) // 全局引用计算耗时的中间件
	r.GET("/", f1)
	r.Run("0.0.0.0:8080")
}

生成证书

  1. 生成ca根证书。生成过程会要求填写密码、CN、ON、OU等信息,记住密码,填写的信息也要和下一步openssl.cnf文件内容一致。
openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3650
  1. 新建并编辑文件openssl.cnf文件。req_distinguished_name中内容按需填写,DNS.1要替换成实际域名。
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
countryName = CN
stateOrProvinceName = Anhui
localityName = Hefei
organizationName = zhangsan
commonName = qw.er.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = qw.er.com
  1. 生成服务端证书
openssl req -newkey rsa:2048 -nodes -keyout server.key -out server.csr -subj "/CN=qw.er.com" -config openssl.cnf

# 提示输入ca私钥的密码
openssl x509 -req -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -extensions v3_req -extfile openssl.cnf
  1. 生成客户端证书
openssl req -newkey rsa:2048 -nodes -keyout client.key -out client.csr -subj "/CN=qw.er.com" -config openssl.cnf

# 提示输入ca私钥的密码
openssl x509 -req -in client.csr -out client.crt -CA ca.crt -CAkey ca.key -CAcreateserial -days 365 -extensions v3_req -extfile openssl.cnf

Nginx配置

nginx反向代理服务端的配置示例如下

server {
    listen 80 ssl;
    server_name qw.er.com;
    ssl_certificate /home/atlas/apps/nginx/certs/qwer/server.crt;
    ssl_certificate_key /home/atlas/apps/nginx/certs/qwer/server.key;
    
    # 校验客户端证书
    ssl_verify_client on;
    ssl_client_certificate /home/atlas/apps/nginx/certs/qwer/ca.crt;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://192.168.0.10:8080; # 服务端地址
    }
}

客户端

以下示例使用命令行传参的方式,指定tls证书文件和是否使用tls通信。

package main

import (
	"crypto/tls"
	"crypto/x509"
	"flag"
	"io"
	"log"
	"net/http"
	"os"
	"time"
)

var (
	cafile  = flag.String("cafile", "ca.crt", "ca 证书文件")
	crtfile = flag.String("crtfile", "client.crt", "客户端tls证书")
	keyfile = flag.String("keyfile", "client.key", "客户端tls私钥")
	url     = flag.String("url", "http://127.0.0.1:8080", "url")
	isTls   = flag.Bool("tls", false, "是否使用tls")
)

func tlsClient(cafile, crtfile, keyfile string) *http.Transport {
	// 加载证书和私钥
	clientCert, err := tls.LoadX509KeyPair(crtfile, keyfile)
	if err != nil {
		log.Fatalf("load key pair error: %s", err)
	}

	// 加载ca证书
	clientCA, err := os.ReadFile(cafile)
	if err != nil {
		log.Fatalf("load ca cert error: %s", err)
	}

	// 创建根证书池并添加ca证书
	caCertPool := x509.NewCertPool()
	caCertPool.AppendCertsFromPEM(clientCA)

	// 创建transport
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{
			Certificates: []tls.Certificate{clientCert},
			RootCAs:      caCertPool,
		},
	}

	return tr
}

func main() {
	flag.Parse()

	req, err := http.NewRequest("GET", *url, nil)
	if err != nil {
		log.Fatalf("new request error: %s", err)
	}
	// 自定义HTTP请求头
	req.Header.Set("myheader1", "myheader1value123")
	// 自定义一个cookie对象
	cookie := &http.Cookie{
		Name: "mycookie",
		Value: "mycookievalue",
	}
	req.AddCookie(cookie)

	client := &http.Client{
		Timeout: time.Second * 5,
	}
	if *isTls {
		client.Transport = tlsClient(*cafile, *crtfile, *keyfile)
	}

	resp, err := client.Do(req)
	if err != nil {
		log.Fatalf("get error: %s", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("read error: %s", err)
	}

	log.Printf("body: %+v", string(body))
}

Nginx配置

server {
    listen 80 ssl;
    server_name qw.er.com;
    ssl_certificate /home/elifen/apps/nginx/certs/qwer/server.crt;
    ssl_certificate_key /home/elifen/apps/nginx/certs/qwer/server.key;
    ssl_verify_client on;
    ssl_client_certificate /home/elifen/apps/nginx/qwer/ca.crt;
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://192.168.0.10:8080;
    }
}

测试

这里需要先确保qw.er.com能被正常解析到nginx服务器,比如配置hosts文件或dns解析记录。

go run main.go -cafile ./ca.crt -crtfile ./client.crt -keyfile ./client.key -url 'https://qw.er.com:80/' -tls

输出示例文章来源地址https://www.toymoban.com/news/detail-630974.html

2023/08/07 17:34:51 body: {"clientIP":"192.168.0.11","cookies":["mycookievalue"],"headers":{"Accept-Encoding":["gzip"],"Connection":["close"],"Cookie":["mycookie=mycookievalue"],"Myheader1":["myheader1value123"],"User-Agent":["Go-http-client/1.1"],"X-Forwarded-For":["192.168.0.11"],"X-Real-Ip":["192.168.0.11"]},"host":"qw.er.com","method":"GET","path":"/","proto":"HTTP/1.0"}

到了这里,关于[golang]使用mTLS双向加密认证http通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • springboot项目开启ssl双向认证且实现相互访问通信浏览器访问通信

    1、服务器端===生成自签名证书** 这段命令是使用Java的keytool工具生成一个RSA算法的密钥对,并将其保存在名为server.jks的密钥库文件中。以下是各个参数的解释: -genkeypair:生成密钥对的命令。 -keyalg RSA:指定使用RSA算法生成密钥对。 -keysize 2048:指定生成的密钥长度为2048位。

    2024年03月21日
    浏览(30)
  • 双向SSL认证证书 生成 jks 步骤, java用jks 发送http请求 方法

    ) 1.证书的 cert.pem 文件 2.key文件 3.key的密钥 这里只显示 liunx 命令 ,windows 的同学可自查 这个命令会提示输入3次密码 ,第一次输入xxx.key的密码 , 第二次提示输入导出密码 自己设就行 ,这里用 changeit 注意: 第一次 不是自己设的 需要用 key文件的密钥 这里会用 上一步骤的导

    2024年02月06日
    浏览(32)
  • Golang实现更安全的HTTP基本认证(Basic Authentication)

    当搜索使用Go的HTTP基本身份验证示例时,我能找到的每个结果都不幸包含了过时的代码(即不使用Go1.4中引入的r.BasicAuth()功能)或不能防止定时攻击。本文介绍如何实现更安全的HTTP基本认证代码。 你一定遇到,当通过浏览器访问一些URL时提示输入用户名和密码。再你输入用户名

    2024年02月10日
    浏览(32)
  • HTTP不同场景下的通信过程和用户上网认证过程分析

    HTTP正常交互过程 1、电脑通过DNS协议将域名解析为IP地址(先本地缓存、再本机Hosts文件、再DNS服务器) 2、电脑与解析出来的外网服务器IP建立TCP三次握手(HTTP默认80端口、HTTPS默认443端口) 3、电脑发出HTTP请求Q(GET或POST) 4、外网服务器回应HTTP 200 OK(会将数据内容进行编码) 5、PC浏览

    2024年01月19日
    浏览(30)
  • 轻松搭建短域名短链接服务系统,可选权限认证,并自动生成证书认证把nginx的http访问转换为https加密访问,完整步骤和代码

    轻松搭建短域名短链接服务系统,可选权限认证,并自动生成证书认证把nginx的http访问转换为https加密访问,完整步骤和代码。 在互联网信息爆炸的时代,网址复杂而冗长,很难在口头告知他人,也难以分享到社交媒体上。因此,网址缩短服务应运而生。本文将介绍其中的一

    2024年01月23日
    浏览(29)
  • JAVA使用RestTemplate类实现SSL双向/单向认证(国际)

    以管理员身份打开Windows PowerShel,通过cd(与linux系统类似)命令进入到JDK的bin目录:如C:Program FilesJavajdk1.8.0_221jrebin,找到目录下有keytool.exe就是正确进入目录了 参数说明: genkey 表示要创建一个新的密钥 alias 表示 keystore 的别名、 keyalg 表示使用的加密算法是 RSA ,一种非

    2024年02月15日
    浏览(27)
  • c++使用OpenSSL基于socket实现tcp双向认证ssl(使用TSL协议)代码实现

    相信各位对OpenSSL库已经不陌生了,目前笔者使用这个库实现了RSA、AES加解密和tcp的双向认证功能,下面来看tcp的双向认证。 简单说双向认证就是:客户端认证服务端是否合法,服务端认证客户端是否合法 。 可以借助于HTTPS来说明,http网络传输协议是超文本的明文协议,也就

    2024年02月06日
    浏览(44)
  • springboot整合https使用自签名证书实现浏览器和服务器之间的双向认证

    效果描述: 本地环境  两台以上电脑  可以实现安装客户端证书的电脑可以访问springboot启动项目,没有安装客户端证书的电脑无法访问springboot启动项目 1.操作:需要安装openssl工具 工具包:Win64OpenSSL_Light-3_3_0.exe 或者Win64OpenSSL_Light-3_3_0.msi  官网:[ Downloads ] - /source/index.html

    2024年04月28日
    浏览(37)
  • 【Spring Security】认证&密码加密&Token令牌&CSRF的使用详解

    🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《Spring Security》。🎯🎯 👉点击这里,就可以查看我的主页啦!👇👇 Java方文山的个人主页 🎁如果感觉还不错的话请给我点赞吧!🎁🎁 💖期待你的加入,一

    2024年02月04日
    浏览(39)
  • AI对话交互场景使用WebSocket建立H5客户端和服务端的信息实时双向通信

    WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许 服务端主动向客户端推送数据 。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 初次接触 WebSocket 的人,都会问同样的问题:我们已经有了 HT

    2024年02月03日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包