gpt4 book ai didi

ruby - 使用 Ruby 实现 HTTPS 证书/公钥固定

转载 作者:数据小太阳 更新时间:2023-10-29 06:58:10 29 4
gpt4 key购买 nike

我有自己的 HTTPS 服务,我正在与另一个 Ruby 应用程序通信。我想在我的应用程序 repo 中的已知时间点保存它的公钥证书,并将服务发送给我的公钥与存储的副本进行比较。要在外部服务器上安装证书,我可能必须将其转换为某种格式,因此服务器发送的文件不会相同。

我想对那个特定的公钥进行某种形式的证书固定。我需要使用 OpenSSL 比较证书的哪些字段,以验证我从服务收到的 PK 是否与从服务器收到的相同?

我想 CN 和签名至少必须匹配。还需要检查什么才能知道我拥有的公共(public)证书与我收到的公共(public)证书完全匹配(即相同的证书)?也许 OSSL 有一个内置的工具来做这件事?

最佳答案

好的,在研究了 OpenSSL 之后,我得出了以下公钥固定的简单实现。其实很简单。不幸的是,我没有看到流行的 HTTP 中间件库(如 Faraday 和 HTTPClient)提供对 verify_callback 的访问权限,它实际上在每个 OpenSSL session 中都可用。

在此示例中,如果 PK 与您之前固定的不匹配, session 将立即终止。请注意,不会使用 OpenSSL::SSL::VERIFY_NONE 调用该 block (无论如何都不应该永远不会使用)。

require 'net/http'
require 'openssl'

# Grab the cert received out of band by pigeon post
cert_code = File.read 'github.com.cer'
downloaded_cert = OpenSSL::X509::Certificate.new(cert_code)

# Tells us whether the private keys on the passed certificates match
# and use the same algo
def same_public_key?(ref_cert, actual_cert)
pkr, pka = ref_cert.public_key, actual_cert.public_key

# First check if the public keys use the same crypto...
return false unless pkr.class == pka.class
# ...and then - that they have the same contents
return false unless pkr.to_pem == pka.to_pem

true
end

# Configure a new HTTP object
http = Net::HTTP.new('github.com', 443)
http.use_ssl = true

# We will verify against our CAs in the root store, and with VERIFY_NONE
# the verify_callback will not fire at all, which defeats the purpose.
http.verify_mode = OpenSSL::SSL::VERIFY_PEER

# verify_callback will be called once for every certificate in the chain,
# starting with the top level certificate and ending with the actual certificate
# presented by the server we are contacting. Returning false from that callback
# will terminate the TLS session. Exceptions within the block will be suppressed.
#
# Citing the Ruby OpenSSL docs:
#
# A callback for additional certificate verification. The callback is invoked
# for each certificate in the chain.
#
# The callback is invoked with two values. preverify_ok indicates if the verification
# was passed (true) or not (false). store_context is an OpenSSL::X509::StoreContext
# containing the context used for certificate verification.
#
# If the callback returns false verification is stopped.
http.verify_callback = lambda do | preverify_ok, cert_store |
return false unless preverify_ok

# We only want to verify once, and fail the first time the callback
# is invoked (as opposed to checking only the last time it's called).
# Therefore we get at the whole authorization chain.
# The end certificate is at the beginning of the chain (the certificate
# for the host we are talking to)
end_cert = cert_store.chain[0]

# Only perform the checks if the current cert is the end certificate
# in the chain. We can compare using the DER representation
# (OpenSSL::X509::Certificate objects are not comparable, and for
# a good reason). If we don't we are going to perform the verification
# many times - once per certificate in the chain of trust, which is wasteful
return true unless end_cert.to_der == cert_store.current_cert.to_der

# And verify the public key.
same_public_key?(end_cert, downloaded_cert)
end

# This request will fail if the cert doesn't match
res = http.get '/'

如果你想做整个证书固定并且证书不受轮换,你可以使用证书指纹:

def same_cert_fingerprint?(ref, actual)
OpenSSL::Digest::SHA256.hexdigest(ref.to_der) == OpenSSL::Digest::SHA256.hexdigest(actual.to_der)
end

编辑:看起来至少 excon 最近实现了这个:

https://github.com/geemus/excon/commit/12437b79bad2a0e51bb4ac5b79c155eb88128245

关于ruby - 使用 Ruby 实现 HTTPS 证书/公钥固定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22093042/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com