C/C++ 使用 CURL 为基于 CloudFlare 的网站验证主机和对等点
C/C++ Validating Host and Peer with CURL for CloudFlare based websites
我正在 CloudFlare 背后的 API 工作,我想完全验证连接以扩展安全性。我现在使用的平台是Windows10.
首先我在 CloudFlare 的网站上下载了一些 CA (Cloudflare_CA.pem, origin_ca_rsa_root.pem, origin_ca_ecc_root.pem),然后在 CURL 中设置所需的选项后尝试联系 API:
struct curl_blob blob;
std::string cf_pem = ...;
blob.data = cf_pem.data();
blob.len = cf_pem.size();
blob.flags = CURL_BLOB_COPY;
curl_easy_setopt(pcurl, CURLOPT_CAINFO_BLOB, &blob);
/* Set the default value: strict certificate check please */
curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYPEER, 1L);
/* Set the default value: strict name check please */
curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYHOST, 2L);
全部失败,出现 PEER 验证错误。然后我用 openssl 测试了以下内容:
openssl s_client -connect website:443
结果是:
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 20 (unable to get local issuer certificate)
之后我发现了一个非常好的命令,它基本上从给定的网站“提取”CA:
openssl s_client -showcerts -servername website -connect website:443 > cacert.pem
最后我还是收到了:
Verify return code: 20 (unable to get local issuer certificate)
然而,cacert.pem 是用其中的一些内容创建的。我在 -----BEGIN CERTIFICATE-----/-----END CERTIFICATE----- 之间获取了第一个证书并将其放入代码中。
验证成功,CURL 不再抱怨。但是,我无法联系 CloudFlare 下的其他主机,这意味着此 CA 不“正常”。
所以我的问题是,该怎么办?我如何为 CloudFlare 找到正确的 CA?
请指教,我相信其他开发人员可能会遇到同样的问题。
查看典型的 Cloudflare 托管站点,证书路径以“DigiCert Baltimore Root”的根 CA 结束。
在 Windows 10 中,应该能够在本地机器证书 -> 受信任的根证书颁发机构 -> 证书 -> Baltimore CyberTrust Root 下找到此证书。
或者,从源代码下载(如果您使用此方法,可能还需要验证指纹)- https://www.digicert.com/kb/digicert-root-certificates.htm
如@David 所述,CloudFlare 使用 DigiCert Root CA(通常)是正确的。然而,正如他们在 their website 上所说的那样,这可能会改变;这意味着如果你硬编码这样检查你的软件可能会在未来的任何时候崩溃。
选项如下:
选项A
从 CloudFlare 购买“高级”证书而不是通用证书,然后 select 您想要的根 CA。这确保(在一定程度上)它是相同的,并且您可以使用该 CA 验证任何域(在我的情况下,我使用 DigiCert Root CA 进行了测试)。
选项 B
使用 mTLS 功能(mTLS 是保护您的 API 的好方法)。这是首选的长期解决方案,但缺点是您需要 supply/embed 证书私钥以及您的软件。但是,如果证书遭到破坏,您可以随时撤销它。
根据我的选择,我还想验证 CA,但是使用 DigiCert Root CA 不适用于 mTLS,这很清楚,因为在您的仪表板上您会看到:
Review Client Certificate for CN=Cloudflare, C=US
Validity Period: 15 Years
Authority: Cloudflare Managed CA for ....
我无法find/download“Cloudflare Managed CA”的根证书。我对此不满意,所以为了确保一切正常,我从这里使用了“Baltimore CyberTrust Root”:https://baltimore-cybertrust-root.chain-demos.digicert.com/info/index.html
现在您也可以使用带有 CA 验证的 CURL 的 mTLS:
// https://baltimore-cybertrust-root.chain-demos.digicert.com/info/index.html
std::string ca_pem = ...
// mtls.cert
std::string cert = ...
// mtls.key
std::string key = ...
struct curl_blob blob;
blob.data = cert.data();
blob.len = cert.size();
blob.flags = CURL_BLOB_COPY;
curl_easy_setopt(pcurl, CURLOPT_SSLCERT_BLOB, &blob);
curl_easy_setopt(pcurl, CURLOPT_SSLCERTTYPE, "PEM");
blob.data = key.data();
blob.len = key.size();
curl_easy_setopt(pcurl, CURLOPT_SSLKEY_BLOB, &blob);
curl_easy_setopt(pcurl, CURLOPT_SSLKEYTYPE, "PEM");
blob.data = ca_pem.data();
blob.len = ca_pem.size();
curl_easy_setopt(pcurl, CURLOPT_CAINFO_BLOB, &blob);
关于 mTLS 的重要说明:
- 确保你付出努力 加密 你的 cert/key 如果你嵌入它
在您的软件中。
- 我不建议您将 cert/key 作为 个人文件提供
在您的软件旁边。
- 即使您在软件中加密 cert/key
总有一种方法可以通过 unpacking/de-onfuscabtion/de-virtualization;任何一个
在运行时......等。我的建议是你立即重新加密
数据或尽快从内存中删除它。
- 万一有人得到你的cert/key,首先生成一个新的cert/key
然后更新您的软件,然后 撤销 现有软件。
那么你应该看看别人是如何得到你的 cert/key 并尝试
缓解这个问题。
如果您不同意任何内容,请随时发表评论and/or/if您有一些suggestions/improvements。
我正在 CloudFlare 背后的 API 工作,我想完全验证连接以扩展安全性。我现在使用的平台是Windows10.
首先我在 CloudFlare 的网站上下载了一些 CA (Cloudflare_CA.pem, origin_ca_rsa_root.pem, origin_ca_ecc_root.pem),然后在 CURL 中设置所需的选项后尝试联系 API:
struct curl_blob blob;
std::string cf_pem = ...;
blob.data = cf_pem.data();
blob.len = cf_pem.size();
blob.flags = CURL_BLOB_COPY;
curl_easy_setopt(pcurl, CURLOPT_CAINFO_BLOB, &blob);
/* Set the default value: strict certificate check please */
curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYPEER, 1L);
/* Set the default value: strict name check please */
curl_easy_setopt(pcurl, CURLOPT_SSL_VERIFYHOST, 2L);
全部失败,出现 PEER 验证错误。然后我用 openssl 测试了以下内容:
openssl s_client -connect website:443
结果是:
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 20 (unable to get local issuer certificate)
之后我发现了一个非常好的命令,它基本上从给定的网站“提取”CA:
openssl s_client -showcerts -servername website -connect website:443 > cacert.pem
最后我还是收到了:
Verify return code: 20 (unable to get local issuer certificate)
然而,cacert.pem 是用其中的一些内容创建的。我在 -----BEGIN CERTIFICATE-----/-----END CERTIFICATE----- 之间获取了第一个证书并将其放入代码中。
验证成功,CURL 不再抱怨。但是,我无法联系 CloudFlare 下的其他主机,这意味着此 CA 不“正常”。
所以我的问题是,该怎么办?我如何为 CloudFlare 找到正确的 CA?
请指教,我相信其他开发人员可能会遇到同样的问题。
查看典型的 Cloudflare 托管站点,证书路径以“DigiCert Baltimore Root”的根 CA 结束。
在 Windows 10 中,应该能够在本地机器证书 -> 受信任的根证书颁发机构 -> 证书 -> Baltimore CyberTrust Root 下找到此证书。
或者,从源代码下载(如果您使用此方法,可能还需要验证指纹)- https://www.digicert.com/kb/digicert-root-certificates.htm
如@David 所述,CloudFlare 使用 DigiCert Root CA(通常)是正确的。然而,正如他们在 their website 上所说的那样,这可能会改变;这意味着如果你硬编码这样检查你的软件可能会在未来的任何时候崩溃。
选项如下:
选项A
从 CloudFlare 购买“高级”证书而不是通用证书,然后 select 您想要的根 CA。这确保(在一定程度上)它是相同的,并且您可以使用该 CA 验证任何域(在我的情况下,我使用 DigiCert Root CA 进行了测试)。
选项 B
使用 mTLS 功能(mTLS 是保护您的 API 的好方法)。这是首选的长期解决方案,但缺点是您需要 supply/embed 证书私钥以及您的软件。但是,如果证书遭到破坏,您可以随时撤销它。
根据我的选择,我还想验证 CA,但是使用 DigiCert Root CA 不适用于 mTLS,这很清楚,因为在您的仪表板上您会看到:
Review Client Certificate for CN=Cloudflare, C=US
Validity Period: 15 Years
Authority: Cloudflare Managed CA for ....
我无法find/download“Cloudflare Managed CA”的根证书。我对此不满意,所以为了确保一切正常,我从这里使用了“Baltimore CyberTrust Root”:https://baltimore-cybertrust-root.chain-demos.digicert.com/info/index.html
现在您也可以使用带有 CA 验证的 CURL 的 mTLS:
// https://baltimore-cybertrust-root.chain-demos.digicert.com/info/index.html
std::string ca_pem = ...
// mtls.cert
std::string cert = ...
// mtls.key
std::string key = ...
struct curl_blob blob;
blob.data = cert.data();
blob.len = cert.size();
blob.flags = CURL_BLOB_COPY;
curl_easy_setopt(pcurl, CURLOPT_SSLCERT_BLOB, &blob);
curl_easy_setopt(pcurl, CURLOPT_SSLCERTTYPE, "PEM");
blob.data = key.data();
blob.len = key.size();
curl_easy_setopt(pcurl, CURLOPT_SSLKEY_BLOB, &blob);
curl_easy_setopt(pcurl, CURLOPT_SSLKEYTYPE, "PEM");
blob.data = ca_pem.data();
blob.len = ca_pem.size();
curl_easy_setopt(pcurl, CURLOPT_CAINFO_BLOB, &blob);
关于 mTLS 的重要说明:
- 确保你付出努力 加密 你的 cert/key 如果你嵌入它 在您的软件中。
- 我不建议您将 cert/key 作为 个人文件提供 在您的软件旁边。
- 即使您在软件中加密 cert/key 总有一种方法可以通过 unpacking/de-onfuscabtion/de-virtualization;任何一个 在运行时......等。我的建议是你立即重新加密 数据或尽快从内存中删除它。
- 万一有人得到你的cert/key,首先生成一个新的cert/key 然后更新您的软件,然后 撤销 现有软件。 那么你应该看看别人是如何得到你的 cert/key 并尝试 缓解这个问题。
如果您不同意任何内容,请随时发表评论and/or/if您有一些suggestions/improvements。