在使用命令gnutls-cli和Ruby代码测试网站的证书锁定时,我发现了一个奇怪的现象.有时,这两种方法获得的证书信任链的数量不同.

命令行gnutls-cli github-cloud.s3.amazonaws.com将显示4:

(我go 掉了一些多余的信息)

Certificate[0] info:
subject `CN=*.s3.amazonaws.com'
pin-sha256="hK1awhGE7onU0O+/0pwyTCX1ngEBhLhdNNtD8P11+xY="

Certificate[1] info:
subject `CN=Amazon,OU=Server CA 1B,O=Amazon,C=US'
pin-sha256="JSMzqOOrtyOT1kmau6zKhgT676hGgczD5VMdRMyJZFA="

Certificate[2] info:
subject `CN=Amazon Root CA 1,O=Amazon,C=US'
pin-sha256="++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI="

Certificate[3] info:
subject `CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies\
pin-sha256="KwccWaCgrnaw6tsrrSO61FgLacNgG2MMLq8GE6+oP5I="

使用Ruby(gihub-cloud.s3.amazonaws.com):

/CN=*.s3.amazonaws.com
hK1awhGE7onU0O+/0pwyTCX1ngEBhLhdNNtD8P11+xY=
/C=US/O=Amazon/OU=Server CA 1B/CN=Amazon
JSMzqOOrtyOT1kmau6zKhgT676hGgczD5VMdRMyJZFA=
/C=US/O=Amazon/CN=Amazon Root CA 1
++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI=

命令行gnutls-cli www.netflix.com将显示2:

Certificate[0] info:
subject `CN=www.netflix.com,O=Netflix\, Inc.
pin-sha256:3TGagkVvINvo827M04z0YZlg5kctebcod1Qwb83pA0s=

Certificate[1] info:
subject `CN=DigiCert TLS RSA SHA256 2020 CA1,O=DigiCert Inc
pin-sha256="RQeZkB42znUfsDIIFWIRiYEcKl7nHwNFwWCrnMMJbVc="

使用拼音(www.netflix.com):

/C=US/ST=California/L=Los Gatos/O=Netflix, Inc./CN=www.netflix.com
3TGagkVvINvo827M04z0YZlg5kctebcod1Qwb83pA0s=
/C=US/O=DigiCert Inc/CN=DigiCert TLS RSA SHA256 2020 CA1
RQeZkB42znUfsDIIFWIRiYEcKl7nHwNFwWCrnMMJbVc=
/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA
r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=

以下是Ruby代码:

#!/usr/bin/env ruby
require 'colorize'
require 'net/http'
require 'openssl'
require 'base64'

domain = "www.netflix.com"

http = Net::HTTP.new(domain, 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.verify_callback = lambda do | preverify_ok, cert_store |
    return false unless preverify_ok
    end_cert = cert_store.chain[0]
    return true unless end_cert.to_der == cert_store.current_cert.to_der
    cert_store.chain.each do |i|
    sha256 = OpenSSL::Digest::SHA256.new
    digest = sha256.digest(i.public_key.to_der)
    spki = Base64.strict_encode64(digest)
    puts i.subject.to_s, spki
    end
    true
end
res = http.get '/'

Ruby代码引用Implementing HTTPS certificate/pubkey pinning with Ruby

谢谢!

推荐答案

让我们以www.netflix.com为例.信任链中使用了三个证书:

  1. 具有公钥PIN 3TGagkVvINvo827M04z0YZlg5kctebcod1Qwb83pA0s=CN=www.netflix.com的证书,其签名方式为:
  2. 具有公钥PIN RQeZkB42znUfsDIIFWIRiYEcKl7nHwNFwWCrnMMJbVc=的DigiCert中间证书CN=DigiCert TLS RSA SHA256 2020 CA1,其签名方式为:
  3. 具有公钥PIN r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=的DigiCert根CA CN=DigiCert Global Root CA

当您建立与远程主机的连接时,远程主机会将#1&;#2发送给您.#3存在于您的设备上,用于验证#1和#2是您可以信任的有效证书.

当您使用OpenSSL Inside Net::HTTP连接到这些主机时,它提供了额外的信息,并打印了完整的证书信任链,这样您就可以知道Root CA签署了什么#2.您没有通过网络与#1和#2一起发送#3,但它无论如何都会告诉您这一点,因为OpenSSL知道它是信任链的一部分.

当您使用gnutls-cli www.netflix.com --print-cert </dev/null 2>&1连接时,它非常简洁,只打印#1和#2--远程主机发送的证书--而是告诉您:

状态:证书受信任.

...基于它,知道您磁盘上的根CA用于签署中间证书,并且中间证书用于签署Netflix证书.

连接或收到的响应没有什么不同;只是工具在运行时打印出的内容有所不同.

Ruby相关问答推荐

从整数中 Select 重复数字的字符串

如何使用 gsub 删除返回字符串中的/和/i?

这是 ruby​​ Regexp 中的错误吗?如何在不使用超时的情况下防止正则表达式匹配中的无限循环?

为什么在 Ruby 中将 0 视为 True?

each_with_index_do 从 1 开始索引

bundler 可以告诉我 Gemfile 中的哪些 gem 有更新的版本

如何记录在 Ruby 程序中调用的每个方法?

需要Ruby

为 Ruby 模块中的每个方法调用执行代码

使用 Ruby MiniTest 之前/之后的套件

在文件中搜索字符串的最佳方法是什么?

如何判断是否安装了gem?

什么时候在 Ruby 中使用 Struct 比使用 Hash 更好?

有没有办法在 RSpec 中取消存根?

将哈希转换为 struct

Ruby 的所有/最佳列表?

如何在 Ruby 中找到除法的余数?

相当于 Ruby 中的通过

获取下周一(或一周中的任何一天)的日期的 Ruby 代码

我安装了一个 gem,但 require 'gemname' 不起作用.为什么?