net/http go 包的类型为 request它定义了一个保存 ConnectionState
的 TLS 字段。不过,描述中的最后一条语句表示 HTTP 客户端会忽略它。我还在调试时检查过,它是nil
。
我需要从中获取值TLSUnique
connection state (或其他地方),以便我可以将其包含在我的证书请求(又名 CSR)中,然后才能注册/将其发送到服务器。
服务器超出了我的问题范围。我关心的是客户。
然后,服务器收到请求,并检查 CSR 的签名以及 TLS 唯一值,证明建立 TLS 连接的客户端与签署 CSR 的客户端是同一客户端。
这是来自RFC 7030 - section 3.5的东西(EST协议(protocol))
[我正在使用的]
我正在试验 GlobalSign EST Go包,他们好像不包含这个功能。
他们的EST-client似乎为每个 EST 操作创建一个 http 客户端,我想我可以改变这种行为并拥有一个客户端来发送所有请求。
但是,由于客户端接受 RoundTripper接口(interface),我无法使用 implementation 之外的底层连接信息.
最佳答案
注意:在这个答案下的评论线程中,很明显OP是在发出客户端请求时获得“TLS唯一”值之后。为此,请参阅my other answer或OP的解决方案。
我决定保留这个答案以供引用,因为它展示了一种有用的技术。
实例化您的http.Server
,然后设置其字段 ConnContext
您需要编写一些函数。
每个由客户端创建到服务器的新 TCP 连接都会调用该函数一次(一个连接能够服务多个请求)。
调用时,它会接收正在服务客户端请求的 net.Conn
,因此您可以将其类型断言为 tls.Conn
,然后调用 ConnectionState
并检查返回值中的 TLSUnique
。
由于您可能需要使该值可用于通过该连接执行的 HTTP 请求,因此可以说最明智的解决方案是将其作为“值”存储在上下文中,该值可通过 获得处理程序代码中的 http.Request
。
为此,在同一回调代码中,您“包装”与请求关联的原始 context.Context
,并将其传递给回调,并从该 TLSUnique 中提取一些值
,以便您可以在用于服务请求的 HTTP 处理程序中检查它。
类似这样的东西(未经测试):
srv := &http.Server{
ConnContext: func(ctx context.Context, c net.Conn) context.Context {
tc := c.(*tls.Conn)
return context.WithValue(ctx, mypkg.MyKey,
tc.ConnectionState().TLSUnique)
},
// other fields, if needed
}
// ... then, in HTTP request handlers:
func MyHTTPReqHandler(rw http.ResponseWriter, req *http.Request) {
uniq := req.Context().Value(mypkg.MyKey)
// verify it's not nil and use
}
检查docs on context.Context.Value
了解如何声明 mypkg.MyKey
。
您可能还需要在提取时实际复制 TLSUique
的值 - 我不知道是否需要这样做。
关于go - 从客户端获取 TLS 信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77570160/