2014-10-18 20 views
7

Naprawdę mam z tym problem, aw tym przypadku nie chcę pominąć filtru verify_authenticity_token, ani zmienić na protect_from_forgery with: :null_session.Nie można zweryfikować autentyczności tokenu CSRF Rails 4 Ajax nawet po ustawieniu nagłówka

W moim metody żądania, ja ustawienie nagłówka z tokenu CSRF następująco:

var token = document.querySelector("meta[name='csrf-token']").content; 
xhr.setRequestHeader("X-CSRF-Token", token); 

oraz poprzez dodanie punktu przerwania w moim kontrolera tak:

def verify_authenticity_token 
    binding.pry 
    super 
end 

I sprawdzeniu, że nagłówek jest ustawiony:

[1] pry(#<MyController>)> request.headers 
=> #<ActionDispatch::Http::Headers:0x007fb227cbf490 
@env= 
    {"CONTENT_LENGTH"=>"202", 
    . 
    . 
    . 
    # omitted headers 
    . 
    . 
    . 
    "HTTP_X_CSRF_TOKEN"=>"the-correct-token-from-meta-tag", 
    . 
    . 
    . 
    } 

Próbowałem również przekazać token jako klucz z kluczem authenticity_token (podobnie jak w przypadku formularzy Rails) i ustaw odpowiedni znacznik X-CSRF-Param (z meta[name="csrf-param"]).

Jednak ja wciąż się:

Can't verify CSRF token authenticity 
Completed 422 Unprocessable Entity in 14638ms 

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken 

Czy ktoś widział tego wcześniej? Wszelkie przemyślenia na temat tego, co może to spowodować?

Z góry dziękuję!

EDIT:

Po dyskusji w komentarzach odpowiedzi marflar jest, wygląda na to token wygasł, gdy wniosek został złożony (testowane przez porównanie do form_authenticity_token). To jeszcze bardziej mnie myli, ponieważ token ustawiony w <%= csrf_meta_tags %> wygasł, gdy pojawi się następne żądanie. Jakieś myśli?

EDIT2: Po rada marflar jest poniżej, dodałem następujące after_filter do mojego app kontrolera:

def set_csrf_headers 
    response.headers['X-CSRF-Param'] = request_forgery_protection_token.to_s 
    response.headers['X-CSRF-Token'] = form_authenticity_token 
end 

I aktualizowany xhr.onload w moim metody żądania w następujący sposób:

namespace.request = = function (type, url, opts, callback) { 

// code omitted 

    xhr.onload = function() { 
    setCSRFHeaders(xhr); 
    var res = {data: JSON.parse(xhr.response), status: xhr.status}; 
    return callback.call(xhr, null, res); 
    }; 

// code omitted 

} 

function setCSRFHeaders (xhr) { 
    var csrf_param = xhr.getResponseHeader('X-CSRF-Param'); 
    var csrf_token = xhr.getResponseHeader('X-CSRF-Token'); 

    if (csrf_param) { 
    document.querySelector("meta[name='csrf-param']").content = csrf_param; 
    } 
    if (csrf_token) { 
    document.querySelector("meta[name='csrf-token']").content = csrf_token; 
    } 
} 

I sprawdzeniu, że Nagłówki odpowiedzi, a następnie meta tagi są poprawnie resetowane, jednak do czasu, gdy pojawi się następne żądanie, nowy token wygasa ponownie. Myśli?

Odpowiedz

1

Domyślam się, że Railsy mogą oczekiwać, że token będzie w kodzie HTML, a nie w nagłówku. Czy możesz tego spróbować? Mam nadzieję, że to pomaga.

Właściwie wydaje mi się, że używasz nieaktualnego tokenu CRSF, ponieważ kopiujesz go z szablonu.

normalnie ustawić go tak jak w mojej działania kontrolera:

response.headers['X-CSRF-Param'] = "#{request_forgery_protection_token}" 
response.headers['X-CSRF-Token'] = "#{form_authenticity_token}" 

Czy żeton na swojej stronie dopasować jeden zwrócony przez wywołanie form_authenticity_token?

UPDATE

W odpowiedzi na Twój komentarz (cytat poniżej):

Właśnie sprawdziłem i masz rację, że jest to nieświeże żeton, który niestety pozostawia mnie jeszcze bardziej zdezorientowany. Meta tagi z danymi CSRF są ustawiane na początkowym ładowaniu strony, w którym to czasie pasują one do form_authenticity_token, ale token jest nieaktualny do czasu wykonania pierwszego żądania ajax. Nie ma więc znaczenia, czy ustawię je w kodzie HTML, czy jako nagłówki, ponieważ wystąpi to w tym samym czasie, a tym samym napotkam ten sam problem z tracącym tokenem przed następnym żądaniem. Dzięki za twoją pomoc - wszelkie pomysły tutaj?

Wpadłem na ten problem podczas wdrażania logowania AJAX. Znalazłem byłem w stanie dokonać żądania POST wszelkiego rodzaju po zalogowaniu, i że muszę poniższy kod, żeby odświeżyć mój Token:

var update_csrf_token_and_param_after_ajax_login = function() { 
    $(document).on("ajaxComplete", function(event, xhr, settings) { 
    var csrf_param = xhr.getResponseHeader('X-CSRF-Param'); 
    var csrf_token = xhr.getResponseHeader('X-CSRF-Token'); 

    if (csrf_param) { 
     $('meta[name="csrf-param"]').attr('content', csrf_param); 
    } 
    if (csrf_token) { 
     $('meta[name="csrf-token"]').attr('content', csrf_token); 
    } 
    }); 
} 

myślę, że prawdopodobnie wystarczy napisać świeży żeton na swojej stronie przed robi POST ...

+0

Nie jestem pewien, czy rozumiem, co masz na myśli przez "w kodzie HTML" - czy możesz podać mi przykład? – mattmattmatt

+0

@ fancycoder Zaktualizowałem swoją odpowiedź, zastanawiam się, czy możesz użyć nieaktualnego tokena – stephenmurdoch

+0

Właśnie sprawdziłem i masz rację, że jest to nieaktualny token, który niestety pozostawia mnie jeszcze bardziej zdezorientowanego. Metatagów z danymi CSRF ustawia się na początkowym załadowaniu strony, w którym to czasie pasują one do 'form_authenticity_token', ale token jest nieaktualny do czasu wysłania pierwszego żądania ajax. Nie ma więc znaczenia, czy ustawię je w kodzie HTML, czy jako nagłówki, ponieważ wystąpi to w tym samym czasie, a tym samym napotkam ten sam problem z tracącym tokenem przed następnym żądaniem. Dzięki za twoją pomoc - wszelkie pomysły tutaj? – mattmattmatt

1

Mam ten sam problem. I kontrolowane Rails kod źródłowy i stwierdził dalej:

  • authenticity_token nie wygasł sam, więc nie ma potrzeby, by poinformować go po każdym ajax żądanie do serwera
  • nie trzeba wysyłać zarówno params[:authenticity_token] i header['x-csrf-token'], tylko jeden z im, szyny sprawdzi params pierwszy, niż header
  • na odświeżenie strony, authenticity_token będzie inny, ale to nie ma znaczenia, ponieważ jest generowany za każdym razem z nakładką jednym czasie rzeczywistym tokena CSRF (na serwerze) jest niezależna od czasu
  • prawdziwy token csrf zapisany w session[:_csrf_token]

Jak widać Token jest przechowywany w sesji i moim problemem było to, że moja sesja wygasła po 24h (prawdopodobnie użytkownik pozostaje na stronie za dzień bez odświeżania)

Jeśli użytkownik jest zalogowany przez ciasteczka lub kilka innych tokenów, w każdym razie dostaje nową sesję, a wraz z nią nowy token CSRF zostanie wygenerowany, a każde żądanie ze starym authenticity_token będzie nieprawidłowe.

Głównym problemem jest sesja, wygasła lub zresetowana.

Powiązane problemy