Go 为任何客户端创建HTTPS测试服务器

Go 为任何客户端创建HTTPS测试服务器,go,Go,由创建的服务器可以验证从其显式创建的客户端的调用: ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client") })) defer ts.Close() client := ts.Client() res, err := client.Get(ts.URL) 在client:=ts.client(

由创建的服务器可以验证从其显式创建的客户端的调用:

ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello, client")
}))
defer ts.Close()

client := ts.Client()
res, err := client.Get(ts.URL)
client:=ts.client()
行中

但是,我有一个生产程序,我想将其设置为使用
ts.URL
作为主机。我越来越

x509: certificate signed by unknown authority
当我调用它时会出错


如何将
ts
设置为与普通HTTPS服务器一样向客户端进行身份验证?

从Go 1.11开始,由于HTTPS的机制,这根本不可能在
\u test.Go
程序中完全实现

但是,您可以执行单个证书签名并生成
server.crt
server.key
文件,然后从本地目录无限期地在
\u test.go
程序中引用它们

一次性生成
.crt
.key
这是Daksh Shah的媒体文章中指定的步骤的简化版,将在Mac上运行

在需要
server.crt
server.key
文件的目录中,创建两个配置文件

server.csr.cnf

v3.ext
然后在该目录中输入以下命令

openssl genrsa-des3-out rootCA.key 2048
#创建密码短语
openssl-req-x509-new-nodes-key rootCA.key-sha256-days 1024-out rootCA.pem-config server.csr.cnf
#输入密码短语
openssl req-new-sha256-nodes-out server.csr-newkey rsa:2048-keyout server.key-config server.csr.cnf
opensslx509-req-in server.csr-CA rootCA.pem-CAkey rootCA.key-CAcreateserial-out server.crt-days 500-sha256-extfile v3.ext
#输入密码短语
最后,通过运行以下命令使系统信任用于对文件进行签名的证书

openrootca.pem
这将在Keychain Acces应用程序中打开证书,该证书将在证书部分中找到,并命名为
localhost
。然后要始终相信它

  • 按enter键打开其窗口
  • 按空格键向下旋转
  • 将“使用此证书时:”更改为“始终信任”
  • 关闭窗口并验证您的决定
注意:我从命令行尝试了许多
安全添加可信证书的排列,尽管它将证书添加到密钥链并将其标记为“始终信任”,但我的Go程序不会信任它。只有GUI方法将系统置于我的Go程序信任证书的状态

使用HTTPS在本地运行的任何Go程序现在都将信任使用
server.crt
server.key
运行的服务器

运行服务器 您可以创建使用这些凭据的
*httptest.Server
实例

func NewLocalHTTPSTestServer(handler http.handler)(*httptest.Server,错误){
ts:=httptest.NewUnstartedServer(处理程序)
证书,错误:=tls.LoadX509KeyPair(“server.crt”,“server.key”)
如果错误!=零{
返回零,错误
}
ts.TLS=&TLS.Config{Certificates:[]TLS.Certificate{cert}
t.StartTLS()
返回ts,无
}
下面是一个示例用法:

func TestLocalHTTPSserver(t*testing.t){
ts,err:=NewLocalHTTPSTestServer(http.HandlerFunc(func)(w http.ResponseWriter,r*http.Request){
fmt.Fprint(w,“你好,客户”)
}))
assert.Nil(t,err)
延迟ts关闭()
res,err:=http.Get(ts.URL)
assert.Nil(t,err)
问候语,err:=ioutil.ReadAll(res.Body)
res.Body.Close()
assert.Nil(t,err)
assert.Equal(t,“你好,客户机”,字符串(问候语))
}

您需要使用正确的证书,或者创建到HTTPS服务器的不安全连接,有点像这样:@Adonis Yeah,在我们的生产代码中启用
unsecureskipverify
的可能性不是一个选项。我如何“使用正确的证书”?这基本上就是我在最初的问题中所要求的。你能澄清一下你的情况吗?从这个问题上看,您似乎在试图使用
httptest.NewTLSServer
来为生产中的安全通信提供服务。@Adrian不,我绝对不会在生产中使用它。我试图在测试项目中生产组件的实际调用时模拟外部生产组件。由于它在调用中与之通信的其他生产组件使用HTTPS,因此我需要来自
NewTLSServer
的模拟服务器也使用HTTPS。@ChrisRedford我从未尝试为httptest生成我自己的证书(或使用有效的证书)。但是,从理论上讲,您可能能够
ts:=NewUnstartedServer
而不是
ts:=newtlserver
。然后,您可以调整
ts.TLS
,这是一个
https://golang.org/pkg/crypto/tls/#Config
(您将加载另一个证书)。然后您可以
ts.StartTLS()
(因为它是一个“未启动的服务器”)。噢,别忘了推迟ts.Close()
。正如我所说,我从未尝试过,但它可能会起作用。不幸的是,“钥匙链访问”部分(如中所述,该条目可用于危害系统其他部分的安全性)。您的代码最好使用一个空白证书池,只向其中添加您的测试CA,而不是尝试使用系统证书池。我甚至对生产服务器也这样做(让管理它们的ops人员选择是使用系统池还是传入显式CA证书集)。
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn

[dn]
C=US
ST=RandomState
L=RandomCity
O=RandomOrganization
OU=RandomOrganizationUnit
emailAddress=hello@example.com
CN = localhost
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1