2014-11-18 28 views
7

Ho un'app Rails che viene eseguita in un contenitore Docker a cui è assegnato un IP 172.17.0.3. Le richieste in arrivo al computer host 51.x.x.x vengono inoltrate all'app rails in 172.17.0.3. In particolare, questo è stato fatto in quanto tale:L'app per le porte inoltro nella Docker sembra causare l'eccezione CSRF

docker run -p 8080:8080 rails_app 

Tuttavia, applicazione Rails tiri Can't verify CSRF token authenticity errore quando un utente tenta di accedere ad alcune delle pagine. Il mio sospetto è che Rails pensi che la richiesta in arrivo sia un attacco, poiché l'ip della destinazione non corrisponde all'ip dell'app Rails - cioè le richieste degli utenti sono indirizzate alla macchina host 51.x.x.x, mentre la posizione effettiva di Rails è a 172.17.0.3

C'è qualche modo per me di dire a Rails che queste richieste sono legittime? Come informazioni aggiuntive, utilizzo devise per l'autenticazione e unicorn come server.

Alcuni di voi potrebbero essere tentati di suggerire di cambiare protect_from_forgery with: :exception in :null_session, ma l'applicazione funziona perfettamente quando non è posizionata dietro un proxy. Inoltre, parte della logica non funzionerà quando ho cambiato quella parte in quanto ritengo che l'impostazione comprometta il modo in cui viene gestita una sessione utente.

Questo è il layout della mia rete:

(user from public network) ----> (proxy) ----> (rails app on a private network) 
     (202.x.x.x)   (51.x.x.x)    (172.x.x.x) 

EDIT: L'applicazione è in development impostazioni. Ecco l'errore che ho ricevuto nei file log/development.log.

Started POST "/register" for 202.x.x.x at 2014-11-18 02:27:11 +0000 
Processing by UsersController#create as HTML 
    Parameters: {"utf8"=>"✓", "authenticity_token"=>"aBG3nIAKK1ALMJ1DDYFlMkmqISMBMZc3iLmaeD2byG8=", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}} 
Can't verify CSRF token authenticity 
Completed 422 Unprocessable Entity in 2ms 

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): 
    actionpack (4.1.4) lib/action_controller/metal/request_forgery_protection.rb:176:in `handle_unverified_request' 
    actionpack (4.1.4) lib/action_controller/metal/request_forgery_protection.rb:202:in `handle_unverified_request' 
    devise (3.4.0) lib/devise/controllers/helpers.rb:251:in `handle_unverified_request' 
    actionpack (4.1.4) lib/action_controller/metal/request_forgery_protection.rb:197:in `verify_authenticity_token' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:424:in `block in make_lambda' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:160:in `call' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:160:in `block in halting' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:166:in `call' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:166:in `block in halting' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:149:in `call' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:149:in `block in halting_and_conditional' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:149:in `call' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:149:in `block in halting_and_conditional' 
activesupport (4.1.4) lib/active_support/callbacks.rb:86:in `run_callbacks' 
    actionpack (4.1.4) lib/abstract_controller/callbacks.rb:19:in `process_action' 
    actionpack (4.1.4) lib/action_controller/metal/rescue.rb:29:in `process_action' 
    actionpack (4.1.4) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action' 
    activesupport (4.1.4) lib/active_support/notifications.rb:159:in `block in instrument' 
    activesupport (4.1.4) lib/active_support/notifications/instrumenter.rb:20:in `instrument' 
    activesupport (4.1.4) lib/active_support/notifications.rb:159:in `instrument' 
    actionpack (4.1.4) lib/action_controller/metal/instrumentation.rb:30:in `process_action' 
    actionpack (4.1.4) lib/action_controller/metal/params_wrapper.rb:250:in `process_action' 
    activerecord (4.1.4) lib/active_record/railties/controller_runtime.rb:18:in `process_action' 
    actionpack (4.1.4) lib/abstract_controller/base.rb:136:in `process' 
    actionview (4.1.4) lib/action_view/rendering.rb:30:in `process' 
    actionpack (4.1.4) lib/action_controller/metal.rb:196:in `dispatch' 
    actionpack (4.1.4) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch' 
    actionpack (4.1.4) lib/action_controller/metal.rb:232:in `block in action' 
    actionpack (4.1.4) lib/action_dispatch/routing/route_set.rb:82:in `call' 
    actionpack (4.1.4) lib/action_dispatch/routing/route_set.rb:82:in `dispatch' 
    actionpack (4.1.4) lib/action_dispatch/routing/route_set.rb:50:in `call' 
    actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:45:in `call' 
    actionpack (4.1.4) lib/action_dispatch/journey/router.rb:71:in `block in call' 
    actionpack (4.1.4) lib/action_dispatch/journey/router.rb:59:in `each' 
    actionpack (4.1.4) lib/action_dispatch/journey/router.rb:59:in `call' 
    actionpack (4.1.4) lib/action_dispatch/routing/route_set.rb:678:in `call' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:186:in `call!' 
    omniauth (1.2.2) lib/omniauth/strategy.rb:164:in `call' 
    warden (1.2.3) lib/warden/manager.rb:35:in `block in call' 
    warden (1.2.3) lib/warden/manager.rb:34:in `catch' 
    warden (1.2.3) lib/warden/manager.rb:34:in `call' 
    rack (1.5.2) lib/rack/etag.rb:23:in `call' 
    rack (1.5.2) lib/rack/conditionalget.rb:35:in `call' 
    rack (1.5.2) lib/rack/head.rb:11:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/params_parser.rb:27:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/flash.rb:254:in `call' 
    rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context' 
    rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:560:in `call' 
    activerecord (4.1.4) lib/active_record/query_cache.rb:36:in `call' 
    activerecord (4.1.4) lib/active_record/connection_adapters/abstract/connection_pool.rb:621:in `call' 
    activerecord (4.1.4) lib/active_record/migration.rb:380:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call' 
    activesupport (4.1.4) lib/active_support/callbacks.rb:82:in `run_callbacks' 
    actionpack (4.1.4) lib/action_dispatch/middleware/callbacks.rb:27:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/reloader.rb:73:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/remote_ip.rb:76:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call' 
    railties (4.1.4) lib/rails/rack/logger.rb:38:in `call_app' 
    railties (4.1.4) lib/rails/rack/logger.rb:20:in `block in call' 
    activesupport (4.1.4) lib/active_support/tagged_logging.rb:68:in `block in tagged' 
    activesupport (4.1.4) lib/active_support/tagged_logging.rb:26:in `tagged' 
    activesupport (4.1.4) lib/active_support/tagged_logging.rb:68:in `tagged' 
    railties (4.1.4) lib/rails/rack/logger.rb:20:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/request_id.rb:21:in `call' 
    rack (1.5.2) lib/rack/methodoverride.rb:21:in `call' 
    rack (1.5.2) lib/rack/runtime.rb:17:in `call' 
    activesupport (4.1.4) lib/active_support/cache/strategy/local_cache_middleware.rb:26:in `call' 
    rack (1.5.2) lib/rack/lock.rb:17:in `call' 
    actionpack (4.1.4) lib/action_dispatch/middleware/static.rb:64:in `call' 
    rack-cors (0.2.9) lib/rack/cors.rb:54:in `call' 
    rack (1.5.2) lib/rack/sendfile.rb:112:in `call' 
    railties (4.1.4) lib/rails/engine.rb:514:in `call' 
    railties (4.1.4) lib/rails/application.rb:144:in `call' 
    rack (1.5.2) lib/rack/lint.rb:49:in `_call' 
    rack (1.5.2) lib/rack/lint.rb:37:in `call' 
    rack (1.5.2) lib/rack/showexceptions.rb:24:in `call' 
    rack (1.5.2) lib/rack/commonlogger.rb:33:in `call' 
    sinatra (1.4.5) lib/sinatra/base.rb:217:in `call' 
    rack (1.5.2) lib/rack/chunked.rb:43:in `call' 
    rack (1.5.2) lib/rack/content_length.rb:14:in `call' 
    unicorn (4.8.3) lib/unicorn/http_server.rb:576:in `process_client' 
    unicorn (4.8.3) lib/unicorn/http_server.rb:670:in `worker_loop' 
    unicorn (4.8.3) lib/unicorn/http_server.rb:525:in `spawn_missing_workers' 
    unicorn (4.8.3) lib/unicorn/http_server.rb:140:in `start' 
    unicorn (4.8.3) bin/unicorn:126:in `<top (required)>' 
+0

Hai mai questo numero? Ho appena creato un ambiente di produzione su una macchina virtuale ubuntu usando contenitori docker ... flask, mysql, nginx e uwsgi. Ricevo anche errori di token CRSF sui moduli. – Chockomonkey

+0

Ho appena immaginato qualcosa di simile anch'io ... Se hai definito SERVER_NAME nella tua configurazione, prova a rimuoverlo. – Chockomonkey

+0

@Chockomonkey Puoi ampliare ciò che intendi? Vuoi dire se hai definito 'SERVER_NAME' come una variabile di ambiente? –

risposta

1

Da una lettura superficiale del 'protect_from_forgery method', troviamo il seguente:

def protect_from_forgery(options = {}) 
    self.forgery_protection_strategy = protection_method_class(options[:with] || :null_session) 
    self.request_forgery_protection_token ||= :authenticity_token 
    prepend_before_action :verify_authenticity_token, options 
    append_after_action :verify_same_origin_request 
    end 

che ha un callback prima che l'azione chiamata 'verify_authenticity_token'. Se guardiamo alla fonte troviamo il seguente:

def verify_authenticity_token 
    mark_for_same_origin_verification! 

    if !verified_request? 
     logger.warn "Can't verify CSRF token authenticity" if logger 
     handle_unverified_request 
    end 
    end 

Da lì si nota che chiama 'verified_request?'.

def verified_request? 
    !protect_against_forgery? || request.get? || request.head? || 
     form_authenticity_token == params[request_forgery_protection_token] || 
     form_authenticity_token == request.headers['X-CSRF-Token'] 
    end 

Data la natura dell'eccezione sollevata, penserei che uno o più di queste condizioni non siano soddisfatte. Non penso che abbia nulla a che fare con l'indirizzamento IP.

0

Se l'app per le tue guide parla non SSL per il tuo proxy, potrebbe esserci un problema a causa del quale ActiveRecord :: SessionStore sta provando a causa di tale scenario.

nostra correzione era quello di rendere il negozio di sessione insicuro:

OurApplication::Application.config.session_store :active_record_store, secure: false

Edit: Ancora nessuna correzione ancora ... Probabilmente stiamo andando a fare la SSL terminare alle applicazioni in contrapposizione al proxy su questo.

Quindi per noi, il problema non aveva nulla a che fare con SSL alla fine. Avevamo una chiamata javascript in esecuzione sul caricamento della prima pagina che stava tentando di eseguire un handshake su un servizio di back-end (tramite un POST), ma non avevamo configurato correttamente il nostro HAProxy per instradare le chiamate a quel servizio, quindi il POST era colpire Rails.Anche se Rails ha restituito un 404 per il percorso, ha anche reimpostato la sessione a causa del token CSRF mancante nella richiesta. La correzione del routing di HAProxy ha risolto il problema.

Il nostro scenario probabilmente non ha quasi nulla a che fare con il tuo, e in Rails 4, hanno reso il comportamento predefinito di protect_from_forgery essere di sollevare un'eccezione invece di reimpostare la sessione. Oh, e abbiamo anche in ultima analisi, dobbiamo impostare il negozio sessione per insicura:

OurApplication::Application.config.session_store :active_record_store, secure: false