如何在 cURL 命令行中信任自签名证书?

l0b*_*0b0 31 curl https

我使用以下 Makefile使用Let's Encrypt 推荐为 foo.localhost 创建了一个自签名证书:

include ../.env

configuration = csr.cnf
certificate = self-signed.crt
key = self-signed.key

.PHONY: all
all: $(certificate)

$(certificate): $(configuration)
    openssl req -x509 -out $@ -keyout $(key) -newkey rsa:2048 -nodes -sha256 -subj '/CN=$(HOSTNAME)' -extensions EXT -config $(configuration)

$(configuration):
    printf "[dn]\nCN=$(HOSTNAME)\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:$(HOSTNAME)\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth" > $@

.PHONY: clean
clean:
    $(RM) $(configuration)
Run Code Online (Sandbox Code Playgroud)

然后我将它分配给了一个网络服务器。我已经验证服务器返回相关证书:

$ openssl s_client -showcerts -connect foo.localhost:8443 < /dev/null
CONNECTED(00000003)
depth=0 CN = foo.localhost
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 CN = foo.localhost
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/CN=foo.localhost
   i:/CN=foo.localhost
-----BEGIN CERTIFICATE-----
[…]
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=foo.localhost
issuer=/CN=foo.localhost
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1330 bytes and written 269 bytes
Verification error: unable to verify the first certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES128-GCM-SHA256
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: […]
    Session-ID-ctx: 
    Master-Key: […]
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket:
    […]

    Start Time: 1529622990
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: no
---
DONE
Run Code Online (Sandbox Code Playgroud)

如何在不修改 /etc 中的任何内容的情况下 让 cURL 信任它--cacert工作,大概是因为没有CA:

$ curl --cacert tls/foo.localhost.crt 'https://foo.localhost:8443/'
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
Run Code Online (Sandbox Code Playgroud)

目标是在开发过程中启用 HTTPS:

  • 如果没有大量工作来在所有开发环境中启用 DNS 验证,我就无法拥有完全类似于生产的证书。因此我必须使用自签名证书。
  • 我显然仍然想让我的开发环境与生产环境尽可能相似,所以我不能简单地忽略任何和所有证书问题。curl -k就像catch (Exception e) {}在这种情况下一样 - 完全不像浏览器与网络服务器交谈。

换句话说,在跑步时curl [something] https://project.local/api/foo我想确信

  1. 如果 TLS 配置正确,除了拥有自签名证书,命令将成功并且
  2. 如果我的 TLS 配置有任何问题,除了拥有自签名证书,该命令将失败。

使用 HTTP 或--insecure不符合第二个标准。

V13*_*V13 19

尝试-k

curl -k https://yourhost/
Run Code Online (Sandbox Code Playgroud)

它应该“接受”自签名证书

  • 问题是如何**信任**自签名证书,而不是如何绕过证书验证。 (30认同)
  • 我写了“我如何让 cURL 信任 **it**”。如果我问你如何打开 SSH 到特定 IP,你会告诉我打开它到每个 IP 吗? (5认同)
  • @l0b0:使 **curl** 信任自签名证书。它还说:“目标是在开发过程中启用 HTTPS”。`curl -k` 实现了两者。自签名证书没有验证,除非您暗示您只想接受某个自签名证书,但这不是问题所说的。你能解释一下你的反对意见是什么吗? (2认同)
  • 从你的帖子里看不出来。里面没有证书的转储。Curl 可能依赖 openssl 进行验证。验证(可能)包括正确的使用标志(例如 ssl 服务器)、CN 名称、日期、链验证、通过 CRL 的吊销检查、通过 OCSP 的吊销检查以及我可能忘记的其他内容。你的帖子没有提到任何这些,也没有显示证书,你一直在更新它。我建议从头开始提出一个好问题并更认真地对待答案,而不是对试图帮助您的每个人无礼。 (2认同)

Tre*_*ntP 12

我遇到了这个问题,完全相同的问题和错误消息,但我使用 GNUTLS 的 certtool 来生成我的证书而不是 openssl。

我的问题是我没有将我的自签名证书设为 CA。它仅被配置为充当 Web 服务器证书。这就是我想要用它做的所有事情,我不打算将它用作 CA 来签署其他证书。

但是,当您想将一个证书作为其他证书的颁发者添加到信任链中时,该证书必须是 CA,否则会被 openssl 拒绝!

对于certtool -i < mycert.crt,我们需要看到这一点:

    Extensions:
            Basic Constraints (critical):
                    Certificate Authority (CA): TRUE
Run Code Online (Sandbox Code Playgroud)

尝试添加-addext basicConstraints=critical,CA:TRUE,pathlen:1到 openssl 命令或修改 cnf 文件以达到相同的效果。

或者,使用 certtool,一次性证书生成要容易得多:

certtool -p --outfile localhost.key
certtool -s --load-privkey localhost.key --outfile localhost.crt
Run Code Online (Sandbox Code Playgroud)

然后根据提示提供证书的 CN 等。当被问及是否用于证书颁发机构时,请说“是”!


小智 7

按照以下步骤操作应该可以解决您的问题:

  1. 下载并保存自签名证书: echo quit | openssl s_client -showcerts -servername "${API_HOST}" -connect "${API_HOST}":443 > cacert.pem
  2. 告诉curl客户这件事:curl --cacert cacert.pem --location --silent https://${API_HOST}

也可以使用 wget 并忽略证书: wget --no-check-certificate https://${API_HOST}

  • -1 我已经尝试过`--cacert`。而且我绝对对*忽略*证书不感兴趣。这是一个可怕的建议。 (11认同)

l0b*_*0b0 5

trustme由urllib3使用,看起来是一个不错的选择。根据他们的自述:

$ # ----- Creating certs -----
$ python -m trustme
Generated a certificate for 'localhost', '127.0.0.1', '::1'
Configure your server to use the following files:
  cert=/tmp/server.pem
  key=/tmp/server.key
Configure your client to use the following files:
  cert=/tmp/client.pem
$ # ----- Using certs -----
$ gunicorn --keyfile server.key --certfile server.pem app:app
$ curl --cacert client.pem https://localhost:8000/
Hello, world!
Run Code Online (Sandbox Code Playgroud)


小智 5

使用提供的解决方案trustme工作得很好,但如果有人有兴趣创建用于学习目的的证书,这些是对我有用的步骤:

  1. 创建根CA:

    openssl req -x509 -sha256 -days 1825 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建服务器私钥:

    openssl genrsa -out localhost.key 2048
    
    Run Code Online (Sandbox Code Playgroud)
  3. 创建证书签名请求:

    openssl req -key localhost.key -new -out localhost.csr
    
    Run Code Online (Sandbox Code Playgroud)
  4. 创建localhost.ext包含以下内容的文件:

    authorityKeyIdentifier=keyid,issuer
    basicConstraints=CA:FALSE
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = localhost
    
    Run Code Online (Sandbox Code Playgroud)

    该文件具有证书的 DNS 配置。这很重要,因为如果 URL 中的名称与证书中的 DNS 不匹配,则 TLS 检查将无法通过。

  5. 使用之前创建的根 CA 签署服务器证书:

    openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in localhost.csr -out localhost.crt -days 365 -CAcreateserial -extfile localhost.ext
    
    Run Code Online (Sandbox Code Playgroud)
  6. 将文件转换crt为以下pem格式:

    openssl x509 -in localhost.crt -out localhost.pem
    openssl x509 -in rootCA.crt -out rootCA.pem
    
    Run Code Online (Sandbox Code Playgroud)

现在您应该能够在服务器中使用localhost.pem和。localhost.key客户端应该使用rootCA.pem连接到服务器。

就我而言,我必须使用jks文件。该pem文件可以转换为jks如下:

//first convert it to pkcs12
openssl pkcs12 -export -in localhost.pem -inkey localhost.key -out serverCertificate.p12 -name "serverCertificate"

//then convert it from pkcs12 to jks
keytool -importkeystore -srckeystore serverCertificate.p12 -srcstoretype pkcs12 -destkeystore localhost.jks
Run Code Online (Sandbox Code Playgroud)

可以使用以下命令查看密钥库中的条目:

keytool -keystore localhost.jks -list
Run Code Online (Sandbox Code Playgroud)

应该localhost.jks在服务器中使用,并且可以使用以下方法测试连接:

curl --cacert rootCA.pem https://localhost:<port>
Run Code Online (Sandbox Code Playgroud)

参考:

  1. https://www.baeldung.com/openssl-self-signed-cert
  2. https://www.digicert.com/kb/ssl-support/openssl-quick-reference-guide.htm
  3. https://www.baeldung.com/convert-pem-to-jks