如何使用密码保护我的 /sidekiq 路由(即需要对 Sidekiq::Web 工具进行身份验证)?

问题描述 投票:0回答:9

我在 Rails 应用程序中使用 sidekiq。 默认情况下,任何人都可以通过在 URL 后附加“/sidekiq”来访问 Sidekiq。 我只想用密码保护/验证 sidekiq 部分。我怎样才能做到这一点?

ruby ruby-on-rails-3 redis rescue sidekiq
9个回答
121
投票

将以下内容放入您的 sidekiq 初始化程序中

require 'sidekiq'
require 'sidekiq/web'

Sidekiq::Web.use(Rack::Auth::Basic) do |user, password|
  # Protect against timing attacks:
  # - See https://codahale.com/a-lesson-in-timing-attacks/
  # - See https://thisdata.com/blog/timing-attacks-against-string-comparison/
  # - Use & (do not use &&) so that it doesn't short circuit.
  # - Use digests to stop length information leaking
  Rack::Utils.secure_compare(::Digest::SHA256.hexdigest(user), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_USER"])) &
  Rack::Utils.secure_compare(::Digest::SHA256.hexdigest(password), ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_PASSWORD"]))
end

在路线文件中:

mount Sidekiq::Web => '/sidekiq'

32
投票

抱歉来晚了,但是 Sidekiq 的 wiki 为 Devise 推荐以下内容:

允许任何经过身份验证的

User
:

# config/routes.rb
authenticate :user do
  mount Sidekiq::Web => '/sidekiq'
end

限制访问

User.admin?

# config/routes.rb
authenticate :user, lambda { |u| u.admin? } do
  mount Sidekiq::Web => '/sidekiq'
end

这个维基帖子还有许多其他安全方案。

这是使用 Rails 5.1.3、Devise 4.3 和 Sidekiq 5.0 进行测试的


15
投票

请参阅 https://github.com/mperham/sidekiq/wiki/Monitoring 下的“安全性”

Sidekiq::Web 使用 Rack::Protection 来保护您的应用程序免受典型的 Web 攻击(例如 CSRFXSS 等)。如果 Rack::Protection 发现您的请求不满足安全要求,它将使您的会话无效并引发

Forbidden
错误。一种可能的情况是您的应用程序在反向代理后面工作,并且没有向其传递重要的标头(
X-Forwarded-For
X-Forwarded-Proto
)。这种情况和解决方案可以在这篇文章issue #2560...

找到

13
投票

如果您要滚动自己的自定义身份验证,则可以使用文档中引用的以下示例此处

# lib/admin_constraint.rb
class AdminConstraint
  def matches?(request)
    return false unless request.session[:user_id]
    user = User.find request.session[:user_id]
    user && user.admin?
  end
end

# config/routes.rb
require 'sidekiq/web'
require 'admin_constraint'
mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new

11
投票

如果您使用 Devise(或其他基于 Warden 的身份验证),则可以执行此操作,假设您的应用程序中有 AdminUser 模型。

# config/routes.rb
# This defines the authentication constraint
constraint = lambda do |request|
               request.env['warden'].authenticate!({ scope: :admin_user })
             end

# This mounts the route using the constraint.
# You could use any other path to make it less obvious
constraints constraint do
  mount Sidekiq::Web => '/sidekiq'
end

7
投票

接受的答案很好,但我认为它可以更安全地实现,正如Sidekiq文档提到的那样(在我发布后对其进行了编辑以演示正确的解决方案)。

为了保护您的应用程序免受定时攻击,请使用

ActiveSupport::SecurityUtils.secure_compare

另外,请使用

&
(请勿使用
&&
),以免短路。

最后,使用摘要来阻止长度信息泄漏(Active Support 5 中默认为

secure_compare
)。

因此,在初始化程序文件中(通常在 Rails 项目中的

config/initializers/sidekiq.rb
中),根据您的 Active Support/Rails 版本,编写以下内容。

主动支持 5+:感谢 Rails PR #24510,传递给

secure_compare
的参数默认通过
Digest::SHA256.hexdigest

require 'active_support/security_utils'
require 'sidekiq'
require 'sidekiq/web'

Sidekiq::Web.use(Rack::Auth::Basic) do |user, password|
  # Protect against timing attacks:
  # - See https://codahale.com/a-lesson-in-timing-attacks/
  # - See https://thisdata.com/blog/timing-attacks-against-string-comparison/
  # - Use & (do not use &&) so that it doesn't short circuit.
  # - Use digests to stop length information leaking
  ActiveSupport::SecurityUtils.secure_compare(user, ENV["SIDEKIQ_ADMIN_USER"]) &
    ActiveSupport::SecurityUtils.secure_compare(password, ENV["SIDEKIQ_ADMIN_PASSWORD"])
end

积极支持4

require 'active_support/security_utils'
require 'sidekiq'
require 'sidekiq/web'

Sidekiq::Web.use(Rack::Auth::Basic) do |user, password|
  # Protect against timing attacks:
  # - See https://codahale.com/a-lesson-in-timing-attacks/
  # - See https://thisdata.com/blog/timing-attacks-against-string-comparison/
  # - Use & (do not use &&) so that it doesn't short circuit.
  # - Use digests to stop length information leaking
  ActiveSupport::SecurityUtils.secure_compare(
    ::Digest::SHA256.hexdigest(user),
    ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_ADMIN_USER"])
  ) &
    ActiveSupport::SecurityUtils.secure_compare(
      ::Digest::SHA256.hexdigest(password),
      ::Digest::SHA256.hexdigest(ENV["SIDEKIQ_ADMIN_PASSWORD"])
    )
end

1
投票

如果您使用 Sorcery 进行身份验证,请参阅以下 如何使用 Rails 路由约束 来保护某些路由。


从巫术维基复制到这里以防止冗余:

本教程展示了如何将 Rails 路由约束与 Sorcery gem 结合使用。感谢 @anthonator 撰写本文!

首先,定义将用于所有约束的

UserConstraint
模块:

module RouteConstraints::UserConstraint
  def current_user(request)
    User.find_by_id(request.session[:user_id])
  end
end

然后,定义该模块后,您可以指定特定的约束类。在这些示例中,第一个路由仅在没有用户登录的情况下才有效,第二个路由仅适用于作为管理员的登录用户:

class RouteConstraints::NoUserRequiredConstraint
  include RouteConstraints::UserConstraint

  def matches?(request)
    !current_user(request).present?
  end
end

class RouteConstraints::AdminRequiredConstraint
  include RouteConstraints::UserConstraint

  def matches?(request)
    user = current_user(request)
    user.present? && user.is_admin?
  end
end

最后,您可以将约束添加到

config/routes.rb

MyApp::Application.routes.draw do

  # other routes …

  root :to => 'admin#dashboard', :constraints => RouteConstraints::AdminRequiredConstraint.new
  root :to => 'home#welcome', :constraints => RouteConstraints::NoUserRequiredConstraint.new

end

0
投票

另一种选择是添加 CanCan 之类的内容和基于角色的特殊访问权限。


0
投票

能够使用设计用户名/密码

这也适用于 API

#config/初始化器/sidekiq.rb

require "sidekiq/web"

Sidekiq::Web.use Rack::Auth::Basic do |username, password|
    User.find_by(username: username)&.valid_password?(password)
end

#config/routes.rb

mount Sidekiq::Web => "/sidekiq"
© www.soinside.com 2019 - 2024. All rights reserved.