我在 Rails 应用程序中使用 sidekiq。 默认情况下,任何人都可以通过在 URL 后附加“/sidekiq”来访问 Sidekiq。 我只想用密码保护/验证 sidekiq 部分。我怎样才能做到这一点?
将以下内容放入您的 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'
抱歉来晚了,但是 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 进行测试的
请参阅 https://github.com/mperham/sidekiq/wiki/Monitoring 下的“安全性”
Sidekiq::Web 使用 Rack::Protection 来保护您的应用程序免受典型的 Web 攻击(例如 CSRF、XSS 等)。如果 Rack::Protection 发现您的请求不满足安全要求,它将使您的会话无效并引发
错误。一种可能的情况是您的应用程序在反向代理后面工作,并且没有向其传递重要的标头(Forbidden
,X-Forwarded-For
)。这种情况和解决方案可以在这篇文章和issue #2560...找到X-Forwarded-Proto
如果您要滚动自己的自定义身份验证,则可以使用文档中引用的以下示例此处。
# 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
如果您使用 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
接受的答案很好,但我认为它可以更安全地实现,正如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
如果您使用 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
另一种选择是添加 CanCan 之类的内容和基于角色的特殊访问权限。
能够使用设计用户名/密码
这也适用于 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"