web-dev-qa-db-fra.com

Comment protéger mon itinéraire/sidekiq par un mot de passe (c’est-à-dire exiger une authentification pour l’outil Sidekiq :: Web)?

J'utilise sidekiq dans mon application Rails . Par défaut, n'importe qui peut accéder à Sidekiq en ajoutant "/ sidekiq" après l'URL . Je souhaite protéger/authentifier par mot de passe uniquement sa partie. Comment puis je faire ça?

52
sagar junnarkar

Mettez ce qui suit dans votre initialiseur sidekiq

require 'sidekiq'
require 'sidekiq/web'

Sidekiq::Web.use(Rack::Auth::Basic) do |user, password|
  [user, password] == ["sidekiqadmin", "yourpassword"]
end

Et dans le fichier de routes:

authenticate :user do
  mount Sidekiq::Web => '/sidekiq'
end
89
bravenewweb

Voir "Sécurité" sous https://github.com/mperham/sidekiq/wiki/Monitoring

Sidekiq :: Web utilise Rack :: Protection pour protéger votre application contre les attaques Web classiques (telles que CSRF , XSS , etc.). Rack :: Protection invaliderait votre session et déclencherait une erreur Forbidden s'il découvrait que votre requête ne répondait pas aux exigences de sécurité. L’une des situations possibles est que votre application fonctionne derrière un proxy inverse et ne lui passe pas d’en-têtes importants (X-Forwarded-For, X-Forwarded-Proto). Une telle situation et solution pourrait être trouvée dans cet article et numéro # 2560 ...

14
Mark Nadig

Désolé de m'être rendu à la soirée, mais le wiki de Sidekiq recommande ce qui suit pour Devise:

Pour autoriser toute User authentifiée:

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

Pour restreindre l'accès à User.admin?

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

Cet article wiki a également de nombreux autres systèmes de sécurité.

Ceci a été testé avec Rails 5.1.3, Devise 4.3 et Sidekiq 5.0

10
Tom Aranda

Si vous utilisez Devise (ou une autre authentification basée sur Warden), vous pouvez le faire en supposant que vous ayez un modèle AdminUser dans votre application.

# 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
10
jaimeiniesta

Si vous utilisez votre propre authentification personnalisée, vous pouvez utiliser l'exemple ci-dessous, qui est référencé dans la documentation ici .

# 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
7
jameswilliamiii

Une autre option serait d'ajouter quelque chose comme CanCan et un accès spécial basé sur les rôles. 

0
toddmetheny

Si vous utilisez Rituel pour l'authentification, voici comment utiliser les contraintes de routages Rails pour protéger certaines routes.


Copié ici du wiki de sorcellerie pour la redondance:

Ce tutoriel montre comment utiliser les contraintes de routages Rails avec Sorcery gem. Merci à @anthonator pour l’avoir écrit!

Commencez par définir le module UserConstraint qui sera utilisé pour toutes les contraintes:

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

Ensuite, une fois ce module défini, vous pouvez spécifier des classes de contraintes spécifiques. Dans ces exemples, le premier itinéraire ne fonctionnera que s'il n'y a pas d'utilisateur connecté, le second ne fonctionnera que pour l'utilisateur connecté qui est un administrateur:

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

Enfin, vous pouvez ajouter les contraintes au 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
AlexChaffee

La réponse acceptée est bonne, mais je pense que cela peut être implémenté de manière plus sécurisée, car la documentation Sidekiq mentionne .

Pour protéger votre application contre les attaques de synchronisation, utilisez ActiveSupport::SecurityUtils.secure_compare.

En outre, utilisez & (ne pas utiliser &&) afin d'éviter tout court-circuit.

Enfin, utilisez des condensés pour empêcher la fuite d'informations de longueur (valeur par défaut de secure_compare dans Active Support 5).

Active Support 5: Merci à Rails PR # 24510 , les paramètres passés à secure_compare passent par Digest::SHA256.hexdigest par défaut.

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

Support actif 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
0
Capripot