我正在尝试使用 POCO 库编写一个向服务器发出 HTTPS 请求的程序。出于测试目的,我正在连接到具有自签名证书的服务器,并且无论如何我都希望允许客户端连接。为了允许这种情况发生,我尝试安装一个 InvalidCertificateHandler
,它是 AcceptCertificateHandler
的一个实例 - 我认为它会接受证书,即使它没有签名。这是我正在使用的代码:
try {
Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> pAcceptCertHandler =
new Poco::Net::AcceptCertificateHandler(true);
Poco::Net::Context::Ptr pContext =
new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "",
"","",Poco::Net::Context::VERIFY_RELAXED,
9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
SSLManager::instance().initializeClient(NULL, pAcceptCertHandler, pContext);
Poco::Net::HTTPSClientSession theSess(myHostName,myHostPort);
// Create the HTTP request object
Poco::Net::HTTPRequest request("POST",
"https://myservername.com/MockServlet/activateEnc","1.1");
// Send the request
std::cout << "Debug point A" << std::endl;
std::ostream& aStream = theSess.sendRequest(request);
std::cout << "Debug point B" << std::endl;
if (aStream.fail()) {
std::cout << "Fail to send HTTP request for activateEnc" << std::endl;
return WSERR_CONNECTION_ERR;
}
} catch (Poco::Exception& exc) {
std::cout << "Exception caught while attempting to connect." << std::endl;
std::cerr << exc.displayText() << std::endl;
return WSERR_CONNECTION_ERR;
}
当我运行这段代码时,我得到以下输出:
Debug point A
Exception caught while attempting to connect.
Certificate validation error: Unacceptable certificate from myservername.com: application verification failure
我的期望是,由于我使用的是 AcceptCertificateHandler,即使证书无效,它也会被接受。我可能做错了什么?
一些注意事项:
- 在 Context 对象构造函数调用中,我为 privateKeyFile、certificateFile 和 caLocation 参数传递了空字符串。我这样做的原因是因为我认为作为客户端我不需要私钥、客户端证书或证书颁发机构证书。也许这就是问题所在?
- 在调用 initializeClient 时,我将 NULL 作为 PrivateKeyPasshraseHandler 传递 - 因为我没有为客户端使用私钥。
- 我没有在使用 Context 对象之前调用 Context::useCertificate()。文档说您需要调用 userCertificate() 或 usePrivateKey(),但我不确定要传递什么,或者这是客户端所必需的,还是仅服务器所必需的。也许这就是问题所在?
最佳答案
我发现如果在 TLS(也可能是 SSL)握手期间通过不等于服务器证书中的主机名的主机名连接到服务器,则会发生同样的错误。在 Poco::Net::HTTPSClientSession theSess(myHostName, myHostPort);
中使用正确的主机名解决这个问题。
在我的例子中,正确的名称在证书的 CN
字段中,我通过以下命令找到了它(例如维基百科):
openssl s_client -connect en.wikipedia.org:443 -tls1 -state
在输出中我们看到:
<...>
Server certificate
-----BEGIN CERTIFICATE-----
MIIKCTCCCPGgAwIBAgIQARQZX2b6/4/WbhJJblFvTzANBgkqhkiG9w0BAQUFADBm
<...>
JW1fZqU0WxncxV8AfXeWfKzI1vkil45CJ4g++7U=
-----END CERTIFICATE-----
subject=/C=US/ST=California/L=San Francisco/O=Wikimedia Foundation, Inc./CN=*.wikipedia.org
<...>
有它:CN=*.wikipedia.org
,所以使用任何 %domain%.wikipedia.org
作为主机名应该没问题。
附言顺便说一下,在 Poco 中可能有一些 SSL 相关错误的异常类,带有更详细的错误消息。
关于c++ - 无法让 POCO HTTPSClientSession 发送请求 - 证书验证失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17354101/