Railsアプリケーションでsidekiqを使用しています。デフォルトでは、URLの後に「/ sidekiq」を追加することで、誰でもSidekiqにアクセスできます。sidekiq部分のみをパスワードで保護/認証したい。どうやってやるの?
8 に答える
以下を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
そしてroutesファイルで:
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
このwiki投稿には、他にも多くのセキュリティスキームがあります。
これは、Rails 5.1.3、Devise 4.3、およびSidekiq5.0を使用してテストされました。
https://github.com/mperham/sidekiq/wiki/Monitoringの「セキュリティ」を参照してください
Sidekiq :: Webは、Rack :: Protectionを使用して、一般的なWeb攻撃(CSRF、XSSなど)からアプリケーションを保護します。Rack :: Protectionは
Forbidden
、リクエストがセキュリティ要件を満たしていないことが判明した場合、セッションを無効にし、エラーを発生させます。考えられる状況の1つは、アプリケーションがリバースプロキシの背後で動作し、重要なヘッダーを渡さないことです(X-Forwarded-For
、X-Forwarded-Proto
)。このような状況と解決策は、この記事と問題#2560で見つけることができます...
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
独自のカスタム認証をロールしている場合は、こちらのドキュメントで参照されている以下の例を使用できます。
# 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
受け入れられた答えは良いですが、 Sidekiqのドキュメントに記載されているように、より安全に実装できると思います (投稿後に正しい解決策を示すために編集されました)。
タイミング攻撃からアプリを保護するには、を使用しますActiveSupport::SecurityUtils.secure_compare
。
- https://codahale.com/a-lesson-in-timing-attacks/を参照してください
- https://thisdata.com/blog/timing-attacks-against-string-comparison/を参照してください
また、ショートしないように&
(使用しないでください)使用してください。&&
そして最後に、ダイジェストを使用して長さ情報の漏洩を阻止します(secure_compare
Active Support 5のデフォルト)。
したがって、初期化ファイル(通常はconfig/initializers/sidekiq.rb
Railsプロジェクト)で、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
認証にSorceryを使用している場合、 Railsルート制約を使用して特定のルートを保護する方法は次のとおりです。
冗長性のためにソーサリーウィキからここにコピーしました:
このチュートリアルでは、SorcerygemでRailsルート制約を使用する方法を示します。それを書いてくれた@anthonatorに感謝します!
まず、UserConstraint
すべての制約に使用されるモジュールを定義します。
module RouteConstraints::UserConstraint
def current_user(request)
User.find_by_id(request.session[:user_id])
end
end
次に、そのモジュールを定義して、特定の制約クラスを指定できます。これらの例では、最初のルートはログインしているユーザーがいない場合にのみ機能し、2番目のルートは管理者であるログインしているユーザーに対してのみ機能します。
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
もう1つのオプションは、CanCanやロールに基づく特別なアクセスなどを追加することです。