2

我正在为一个项目编写集成测试代码,它在服务器上设置了一个新的安全虚拟主机。服务器支持 SNI。但是,由于测试代码是在开发环境中运行的,因此主机名的 DNS 记录没有正确设置。因此,为了检查是否返回了正确的证书,使用 curl 我必须这样做

curl -i --cacert sample_ca.crt --resolve example.com:443:1.2.3.4 https://example.com/

或通过 openssl 实用程序

openssl s_client -connect 1.2.3.4:443 -servername example.com

我设法找到了在 ruby​​ 中重现用例的参考,如下所示

context = OpenSSL::SSL::SSLContext.new
context.ca_file = 'sample_ca.crt'
context.verify_mode = OpenSSL::SSL::VERIFY_PEER

tcp_client = TCPSocket.new('1.2.3.4', 443)
ssl_client = OpenSSL::SSL::SSLSocket.new(tcp_client, context)
ssl_client.hostname = 'example.com'
ssl_client.connect

cert = OpenSSL::X509::Certificate.new(ssl_client.peer_cert)
pkey = OpenSSL::PKey.read(File.read(''sample_pkey.key))

if cert.check_private_key(pkey) then
  ssl_client.print "GET #{uri} HTTP/1.1\r\n"
  ssl_client.print "Host: example.com\r\n\r\n"
  header, body = ssl_client.read.split("\r\n\r\n")
else
  header, body = ['', '']
end

ssl_client.sysclose
tcp_client.close

我最初想用纯 net/http 来实现它,但是除非我为 example.com 正确设置了 DNS(我无权访问 DNS 设置,所以我通过编辑我的主机文件来作弊),它不会无论我如何尝试都可以工作。考虑到我对 ruby​​ 比较陌生,我想知道是否有办法只使用 net/http?

4

1 回答 1

1

我不想这么说,但看着这个,看起来一个人必须修改补丁TCPSocket::open,以便它将给定的地址解析为其他东西,而不是它会做的事情。TCPSocket在传递给 SSL 之前,无法拦截和更改对象。见HTTP#connect方法来源。我认为猴子补丁TCPSocket是一个非常糟糕的主意,只能用于非生产测试。

于 2016-04-27T12:49:30.560 回答