60

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

4

8 回答 8

116

将以下内容放入您的 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'
于 2012-11-16T02:15:16.997 回答
29

很抱歉迟到了,但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

此 wiki 帖子还有许多其他安全方案。

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

于 2017-10-23T14:19:18.163 回答
15

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

Sidekiq::Web 使用Rack::Protection来保护您的应用程序免受典型的 Web 攻击(例如CSRFXSS等)。Forbidden如果发现您的请求不满足安全要求,Rack::Protection 将使您的会话无效并引发错误。一种可能的情况是让您的应用程序在反向代理后面工作,并且没有将重要的标头传递给它(X-Forwarded-ForX-Forwarded-Proto)。这种情况和解决方案可以在这篇文章问题#2560中找到......

于 2012-09-04T15:30:45.510 回答
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
于 2015-02-17T21:36:30.593 回答
11

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

# 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
于 2016-09-14T18:08:07.367 回答
4

公认的答案很好,但我认为它可以更安全地实施,正如Sidekiq 文档所提到 的(在我发布后它被编辑以展示正确的解决方案)。

要保护您的应用免受计时攻击,请使用ActiveSupport::SecurityUtils.secure_compare.

另外,使用&(不要使用&&)以免短路。

最后,使用摘要来阻止长度信息泄漏(secure_compareActive Support 5 中的默认值)。

因此,在初始化文件中,通常在config/initializers/sidekiq.rbRails 项目中,根据您的 Active Support/Rails 版本,编写以下内容。

Active Support 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
于 2019-01-25T17:53:51.667 回答
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
于 2015-05-07T15:28:35.180 回答
0

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

于 2015-04-07T17:19:48.803 回答