如何在 Ruby 2.2 上删除不安全密码来强化 Rails+webrick+https

2024-05-18

更新:首先,我的测试代码没有充分显示 ruby​​ 2.4 看到 :SSLCiphers 选项,而 ruby​​ 2.2 没有。我编辑了下面的示例代码以清楚地表明这一点。

更新:由于我的问题未能得到社区的任何帮助,我继续前进,两天后找到了解决方案,我将其包含在下面。

我有一个基于 Ruby 2.2 和 Webrick 的小型 Rails 3 应用程序,它可以处理小型负载,因此不需要“真正的”Web 服务器的复杂性。它已被修补以支持 https 连接以进行安全登录,但默认情况下,它接受许多旧的弱密码,我想禁止这些密码。虽然将 ruby​​ 升级到 2.4 提供了新的强化选项来实现此目的,但我无法立即切换到较新的 ruby​​。因此,我尝试对 ruby​​ 2.2 的 webrick/ssl.rb 进行猴子修补,以添加其中几个选项::SSLVersion 和:SSLCiphers。我只取得了部分成功:虽然 :SSLVersion 似乎可以工作,但 :SSLCiphers 却不能。

首先,以下示例基于此处的答案显示了 Ruby 2.4 上的成功强化https://stackoverflow.com/a/23283909/6588873 https://stackoverflow.com/a/23283909/6588873但也结合了这里找到的一些建议:https://gist.github.com/tam7t/86eb4793e8ecf3f55037 https://gist.github.com/tam7t/86eb4793e8ecf3f55037除了最初我们会过于激进并排除 AES128 只是为了显示 :SSLCiphers 选项的工作原理(因为 Ruby 2.4 中的 openssl 版本默认情况下禁用所有 SHA1 密码)。

#!/usr/bin/env ruby.exe
# script/rails:
require 'rails/commands/server'
require 'rack'
require 'webrick'
require 'webrick/https'

module Rails
     class Server < ::Rack::Server
         SSL_ENABLED=true
         def default_options
             # Don't use SSLv3
             no_ssl_3 = OpenSSL::SSL::OP_NO_SSLv3
             # Don't use SSLv2
             no_ssl_2 = OpenSSL::SSL::OP_NO_SSLv2
             # Don't use compression (CRIME CVE-2012-4929)
             no_ssl_compression = OpenSSL::SSL::OP_NO_COMPRESSION
             ssl_options = no_ssl_2 + no_ssl_3 + no_ssl_compression

             super.merge({
                 :Port => 3002,
                 :environment => (ENV['RAILS_ENV'] || "development").dup,
                 :daemonize => false,
                 :debugger => false,
                 :config => File.expand_path("config.ru"),
                 :SSLEnable => true,
                 :SSLVerifyClient => OpenSSL::SSL::VERIFY_NONE,
                 :SSLPrivateKey => OpenSSL::PKey::RSA.new(
                        File.open(File.expand_path("../cert/test.cert.key",__FILE__)).read),
                 :SSLCertificate => OpenSSL::X509::Certificate.new(
                        File.open(File.expand_path("../cert/test.cert.crt",__FILE__)).read),
                 :SSLCertName => [["CN", WEBrick::Utils::getservername]],
                 :SSLOptions => ssl_options,
                 :SSLCiphers => 'TLSv1.2:!aNULL:!eNULL:!AES128',
                 :SSLVersion => :TLSv1_2,
             })
         end
     end
end

APP_PATH = File.expand_path('../../config/application',  __FILE__)
require File.expand_path('../../config/boot',  __FILE__)
require 'rails/commands'

这是应用了上述补丁的 sslscan 输出的摘录,显示了受支持的密码的简短列表,其中包含不安全的密码和已删除的过时 TLS 版本(尽管默认情况下它们无论如何都会被删除,因此 !AES128 只是为了显示该选项的原理证明)作品)。

  Supported Server Cipher(s):
Preferred TLSv1.2  256 bits  ECDHE-RSA-AES256-GCM-SHA384   Curve P-256 DHE 256
Accepted  TLSv1.2  256 bits  ECDHE-RSA-AES256-SHA384       Curve P-256 DHE 256
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-GCM-SHA384     DHE 1024 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-SHA256         DHE 1024 bits
Accepted  TLSv1.2  256 bits  AES256-GCM-SHA384
Accepted  TLSv1.2  256 bits  AES256-SHA256

接下来,我将 :SSLCiphers 更改为我想要的实际字符串,因为我实际上对 AES128 很满意。我只想排除旧版 openssl 默认情况下不排除的所有旧 SHA1 密码:

             :SSLCiphers => 'TLSv1.2:!aNULL:!eNULL!SHA',

然后准备我的反向移植,插入到上面所示的 Rails::Server 补丁之后。以下内容直接从 Ruby 2.2 的 webrick/ssl.rb 中提取,但添加了 Ruby 2.4 中的两个新选项,并通过 WEBrick::GenericServer#setup_ssl_context() 传递到 ruby​​-openssl:

if RUBY_VERSION < '2.4'
  module WEBrick
    module Config
      svrsoft = General[:ServerSoftware]
      osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
      SSL = {
        :ServerSoftware       => "#{svrsoft} OpenSSL/#{osslv}",
        :SSLEnable            => false,
        :SSLCertificate       => nil,
        :SSLPrivateKey        => nil,
        :SSLClientCA          => nil,
        :SSLExtraChainCert    => nil,
        :SSLCACertificateFile => nil,
        :SSLCACertificatePath => nil,
        :SSLCertificateStore  => nil,
        :SSLTmpDhCallback     => nil,
        :SSLVerifyClient      => ::OpenSSL::SSL::VERIFY_NONE,
        :SSLVerifyDepth       => nil,
        :SSLVerifyCallback    => nil,   # custom verification
        :SSLTimeout           => nil,
        :SSLOptions           => nil,
        :SSLCiphers           => nil,
        :SSLVersion           => nil,
        :SSLStartImmediately  => true,
        # Must specify if you use auto generated certificate.
        :SSLCertName          => nil,
        :SSLCertComment       => "Generated by Ruby/OpenSSL"
      }
      General.update(SSL)
    end

    class GenericServer
      def setup_ssl_context(config) # :nodoc:
        unless config[:SSLCertificate]
          cn = config[:SSLCertName]
          comment = config[:SSLCertComment]
          cert, key = Utils::create_self_signed_cert(1024, cn, comment)
          config[:SSLCertificate] = cert
          config[:SSLPrivateKey] = key
        end
        ctx = OpenSSL::SSL::SSLContext.new
        ctx.key = config[:SSLPrivateKey]
        ctx.cert = config[:SSLCertificate]
        ctx.client_ca = config[:SSLClientCA]
        ctx.extra_chain_cert = config[:SSLExtraChainCert]
        ctx.ca_file = config[:SSLCACertificateFile]
        ctx.ca_path = config[:SSLCACertificatePath]
        ctx.cert_store = config[:SSLCertificateStore]
        ctx.tmp_dh_callback = config[:SSLTmpDhCallback]
        ctx.verify_mode = config[:SSLVerifyClient]
        ctx.verify_depth = config[:SSLVerifyDepth]
        ctx.verify_callback = config[:SSLVerifyCallback]
        ctx.timeout = config[:SSLTimeout]
        ctx.options = config[:SSLOptions]
        ctx.ciphers = config[:SSLCiphers]
        ctx.ssl_version = config[:SSLVersion]
        ctx
      end
    end
  end
end

启动时,我看到以下重新定义警告。第一个,我预料到了。第二个我不确定,但我认为还可以:

script/rails:47: warning: already initialized constant WEBrick::Config::SSL
C:/Ruby226/lib/ruby/2.2.0/webrick/ssl.rb:62: warning: previous definition of SSL was here

现在,虽然 sslscan 现在指示遵守 SSLVersion(即不接受 TLS 1.0 或 1.1),但 SSLCiphers 选项似乎根本没有执行任何操作,即仍然接受 SHA 密码:

  Supported Server Cipher(s):
Preferred TLSv1.2  256 bits  DHE-RSA-AES256-GCM-SHA384     DHE 1024 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-SHA256         DHE 1024 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-SHA            DHE 1024 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-CAMELLIA256-SHA       DHE 1024 bits
Accepted  TLSv1.2  256 bits  AES256-GCM-SHA384
Accepted  TLSv1.2  256 bits  AES256-SHA256
Accepted  TLSv1.2  256 bits  AES256-SHA
Accepted  TLSv1.2  256 bits  CAMELLIA256-SHA
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-GCM-SHA256     DHE 1024 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-SHA256         DHE 1024 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-SHA            DHE 1024 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-SEED-SHA              DHE 1024 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-CAMELLIA128-SHA       DHE 1024 bits
Accepted  TLSv1.2  128 bits  AES128-GCM-SHA256
Accepted  TLSv1.2  128 bits  AES128-SHA256
Accepted  TLSv1.2  128 bits  AES128-SHA
Accepted  TLSv1.2  128 bits  SEED-SHA
Accepted  TLSv1.2  128 bits  CAMELLIA128-SHA

而我期望的是:

  Supported Server Cipher(s):
Preferred TLSv1.2  256 bits  DHE-RSA-AES256-GCM-SHA384     DHE 1024 bits
Accepted  TLSv1.2  256 bits  DHE-RSA-AES256-SHA256         DHE 1024 bits
Accepted  TLSv1.2  256 bits  AES256-GCM-SHA384
Accepted  TLSv1.2  256 bits  AES256-SHA256
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-GCM-SHA256     DHE 1024 bits
Accepted  TLSv1.2  128 bits  DHE-RSA-AES128-SHA256         DHE 1024 bits
Accepted  TLSv1.2  128 bits  AES128-GCM-SHA256
Accepted  TLSv1.2  128 bits  AES128-SHA256

事实上,我将 :SSLCiphers 更改为任何有效甚至无效值并不重要。显然,仅仅更新 ruby​​ 是不够的。

我这个向后移植哪里出了问题?我还可以尝试其他什么方法来达到相同的结果吗?我似乎非常接近这里的解决方案,在我们的 Ruby 版本和 webrick 的限制下工作,这对我来说很难摆脱。

解决方案:

我插入了调试打印语句来查看 SSLCiphers 值在哪里“丢失”。尽管我的测试显示 WEBrick 方面一切正常,但在 OpenSSL 类中,当设置 SSL 侦听器时,似乎传入了错误的密码列表(即默认值而不是覆盖值)。

当查看 OpenSSL API 寻找有关如何获取有关失败的更多信息的线索时,我发现OpenSSL::SSL::SSLContext#set_params http://ruby-doc.org/stdlib-2.2.6/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html#method-i-set_params,一种将哈希值作为参数的方法,其中包含 SSLContext 的任何参数以设置新值。因此,我实验性地替换了我的猴子补丁 WEBrick::GenericServer#setup_ssl_context 以使用它并传递要更改的所有值的哈希值,而不是替换每个设置的 ctx.= config:[:] (直接从原始 WEBrick 代码中提取;甚至在 Ruby 2.4 中这一点没有改变)。

我的结果?成功!使用更改 SSLContext 对象的替代方法,我能够使 :SSLCiphers 覆盖值“stick”

if RUBY_VERSION < '2.4'
  require 'webrick/ssl'

  module WEBrick
    module Config
      svrsoft = General[:ServerSoftware]
      osslv = ::OpenSSL::OPENSSL_VERSION.split[1]
      SSL = {
        :ServerSoftware       => "#{svrsoft} OpenSSL/#{osslv}",
        :SSLEnable            => false,
        :SSLCertificate       => nil,
        :SSLPrivateKey        => nil,
        :SSLClientCA          => nil,
        :SSLExtraChainCert    => nil,
        :SSLCACertificateFile => nil,
        :SSLCACertificatePath => nil,
        :SSLCertificateStore  => nil,
        :SSLTmpDhCallback     => nil,
        :SSLVerifyClient      => ::OpenSSL::SSL::VERIFY_NONE,
        :SSLVerifyDepth       => nil,
        :SSLVerifyCallback    => nil,   # custom verification
        :SSLTimeout           => nil,
        :SSLOptions           => nil,
        :SSLCiphers           => nil,
        :SSLVersion           => nil,
        :SSLStartImmediately  => true,
        # Must specify if you use auto generated certificate.
        :SSLCertName          => nil,
        :SSLCertComment       => "Generated by Ruby/OpenSSL"
      }
      General.update(SSL)
    end

    class GenericServer
      def setup_ssl_context(config) # :nodoc:
        unless config[:SSLCertificate]
          cn = config[:SSLCertName]
          comment = config[:SSLCertComment]
          cert, key = Utils::create_self_signed_cert(1024, cn, comment)
          config[:SSLCertificate] = cert
          config[:SSLPrivateKey] = key
        end
        ctx = OpenSSL::SSL::SSLContext.new
        ctx.set_params({
          key: config[:SSLPrivateKey],
          cert: config[:SSLCertificate],
          client_ca: config[:SSLClientCA],
          extra_chain_cert: config[:SSLExtraChainCert],
          ca_file: config[:SSLCACertificateFile],
          ca_path: config[:SSLCACertificatePath],
          cert_store: config[:SSLCertificateStore],
          tmp_dh_callback: config[:SSLTmpDhCallback],
          verify_mode: config[:SSLVerifyClient],
          verify_depth: config[:SSLVerifyDepth],
          verify_callback: config[:SSLVerifyCallback],
          timeout: config[:SSLTimeout],
          options: config[:SSLOptions],
          ciphers: config[:SSLCiphers],
          ssl_version: config[:SSLVersion],
        })
        ctx
      end
    end
  end
end

安装此补丁后,sslscan 输出与上面显示的预期输出相匹配。


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 Ruby 2.2 上删除不安全密码来强化 Rails+webrick+https 的相关文章

  • Rails:验证字符串的最小和最大长度,但允许其为空白

    我有一个想要验证的字段 我希望该字段能够留空 但如果用户输入数据 我希望它采用某种格式 目前我在模型中使用以下验证 但这不允许用户将其留空 validates length of foo maximum gt 5 validates len
  • RuntimeError:无法修改冻结的数组(Rollbar、Rails 5.1 升级)

    升级到rails 5后无法使用rspec和rollbar 创建 Rails 4 应用程序 升级 gemfile 以使用 Rails 5 尝试添加防滚杆 gem support 标准配置 环境 rb Load the Rails applic
  • 使用brew时出现“错误的解释器”错误

    当我尝试运行任何 brew 命令时 出现此错误 Holger Sindbaeks MacBook Air holgersindbaek brew help bash usr local bin brew usr bin ruby bad i
  • $ bundle exec rake db:reset 命令提升无法删除 db/development.sqlite3

    我试着跑 bundle exec rake db reset并在控制台上发现以下内容 Couldn t drop db development sqlite3
  • Rails 中的会话、子域和 authlogic 问题

    我有一个带有 authlogic 身份验证的 Rails 应用程序和一个使用 subdomain fu 构建的 username domain com 结构 但是当从domain com转到username domain com时 我的会话
  • Rails 5 - 在 gem 上充当 Taggable - 简单表单集合选择已定义的标签列表

    我正在尝试学习如何将 Acts as Taggable On gem 与 Rails 5 一起使用 我使用简单的表格作为表格 我认为部分问题是由于提案和 randd fields 之间的模型没有关联而产生的 我有名为 Proposal 和
  • 导入证书时CRYPT_E_NOT_FOUND

    我正在尝试自动生成证书签名请求的过程 然后从 Windows Server 2012 R2 服务器上的 CA 导入响应 以用作 IIS 中 SSL 绑定的证书 我能够生成 CSR 然后将其提供给安全团队 然后安全团队为我提供响应 然后导入
  • Rails ActiveRecord:是否可以组合 :include 和 :conditions 查询?

    想象一下我有 wiki 文章 有很多修订 我想通过数据库使用 ActiveRecord 进行查询 该查询仅返回那些在过去 24 小时内更新过修订的文章 这样的事可能吗 我想它会是这样的 Articles find all include g
  • 默认更新嵌套属性

    我尝试更新 iProduction 这是生产中的嵌套表单 但此行出现参数错误 参数数量错误 0 代表 1 生产 update iproducts attributes cow id cow 我的创作动作制作 def create produ
  • 使用ajax轮询服务器

    我正在建立一个网站 该网站有一个用户可以互相发送消息的系统 我希望这样当登录用户收到消息时 他会在屏幕上看到一些更新告诉他这一点 这些消息不必是实时的 所以我认为我不想用彗星或主宰之类的东西来推动 相反 我很乐意每隔一分钟左右轮询一次服务器
  • Rails 4 - 带有 dependent-fields-rails 的条件 JS

    我正在尝试弄清楚如何在我的 Rails 4 应用程序中使用 dependent fields rails gem 我迷路了 我已将 underscore js 包含在我的供应商 javascripts 文件夹中 并更新了我的 applica
  • A has_many Bs 其中 B 没有主键

    我有型号 A 和 B A has many B 并且 B 属于 A 到目前为止 一切都很好 除了我指定 B 没有主键 我不打算修改或删除单个 B 行 并且我预计会有数百万到数十亿的 B 行 因此省略主键将非常方便 节省空间 创建 B 表的迁
  • Flash观看后不清晰

    这是我的创建动作 它创建一个新的 Message 实例 并通过模型验证进行检查 然后有一个简单的 if else 循环 如果模型验证已完成 则发送消息 如果要发送另一个视图 则渲染 新 视图 如果模型验证未得到满足 它只会再次呈现 新 视图
  • Ruby on Rails 从视图路由到控制器中的自定义方法

    我有一个控制器名称帖子 在我的 config routes rb 我用过这个 resources posts app controllers posts controller rb class PostsController lt Appl
  • 如何使用 AngularJS、Devise 和 UI Router 全局实现身份验证?

    我对 Angular 很陌生 所以这可能是一个新手问题 我正在尝试实现一个简单的任务管理器 只是一个练习 以 Rails 作为后端 以 Angular 作为前端 到目前为止 我遵循了教程 一切正常 现在我想在全球范围内实施身份验证 这意味着
  • 如何生成devise gem的注册控制器

    我已经设置了 Devise 我已经在 user rb 文件中设置了以下代码 def self create auto password generated password Devise friendly token first 8 sel
  • Android - 除了普通 SSL 证书之外还验证自签名证书

    我有一个通过 SSL 调用 Web 服务的 Android 应用程序 在生产中 我们将拥有由受信任的 CA 签名的普通 SSL 证书 但是 我们需要能够支持自签名证书 由我们自己的 CA 签名 我已经成功实施了接受自签名证书的建议解决方案
  • 如何使用自签名证书为 TLS 创建 iOS NWConnection?

    我正在尝试将 Apple 的新 NWConnection 类用于我的 MQTT 客户端 为了进行测试 我需要能够创建到本地测试代理的 TLS 连接 该代理具有自签名证书 到目前为止 我只是使用以下命令设置连接 self connection
  • 在 Rails 中,我可以通过委托方法订购查询吗?

    我在通过委托方法订购查询时遇到困难 我的任务是帮助将一个相当大的 Rails 3 应用程序升级到 Rails 4 我在索引操作中遇到了这个查询 我知道这些对象的命名是可怕且令人困惑的 measurements controller rb d
  • 使用 RSpec 进行 Rails 片段缓存测试

    我觉得这是一个没有太多记录的主题 至少我在这里找到最佳实践时遇到了很多麻烦 我使用 cache key 在视图中进行片段缓存 tbody employees each do employee cache employee do tr emp

随机推荐