2013-07-05 17 views
25

Właśnie przełączyłem się z Rails 3.2 na Rails 4. Próbuję się upewnić, że jestem maksymalnie szybki w kwestiach bezpieczeństwa, i martwię się teraz sesjami. Wygląda na to, że Rails 4 przestał obsługiwać naprawdę wszystko, Z WYJĄTKIEM sesji opartych na plikach cookie, ale wygląda na to, że nie można zapobiec trwającym nieprzerwanie sesjom opartym na plikach cookie. Czytałem kilka artykułów, ale ten jest najbardziej oficjalny: http://guides.rubyonrails.org/security.html#session-expiry. Zwróć uwagę, że zwracają uwagę, że jest to problem związany z sesjami opartymi na plikach cookie, a następnie poprawiają je dla sesji bazujących na bazach danych (które są obecnie przestarzałe).Szyny 4: Wygaśnięcie sesji?

Jestem naprawdę zdezorientowany. Chcę móc uniemożliwić osobie atakującej uzyskanie pliku cookie, który zapewni mu stały dostęp do mojej witryny chronionej przez logowanie. Oczywiście mogę ustawić: expire_after in initializers/session_store.rb, ale chyba nie mam racji, że po prostu ustawia wygaśnięcia ciasteczka, które jest po stronie klienta i łatwo zmienić przez atakującego, aby sesja mogła żyć wiecznie. Oczywiście mogę poprawić sytuację, wymuszając stosowanie SSL, stosując bezpieczne pliki cookie i wymuszając tylko HTTP, ale nigdy nie będzie to pełna ochrona, dopóki nie wyegzekwuję wygaśnięcia sesji.

W jaki sposób mogę rozwiązać ten problem, gdy Rails wycofuje jedyne sposoby na sesje po stronie serwera?

Wiem, że aktywne sesje nagrań zostały przeniesione do klejnotu i są nadal dostępne, ale faktem jest, że został wycofany. Rozwiązanie powinno być możliwe bez wprowadzania większej liczby zależności lub przynajmniej bez używania przestarzałych funkcji.

+0

Dlaczego ta notatka spada (bez komentarzy) kilka lat po zadaniu? – Kyle

+0

To bardzo ważne pytanie - a przewodniki po Railsach są ... no ... czym one są. Byłbym zadowolony, znając dobrą odpowiedź na twoje pytanie, ponieważ całkowicie rozumiem, dlaczego jesteś zdezorientowany przez to, co jeszcze istnieje, nawet w najnowszej "krawędzi". – silverdr

Odpowiedz

34

Railsy mają "sesyjne" pliki cookie dotyczące sesji. Aby zapobiec manipulowaniu hashami sesji, obliczenia są obliczane na podstawie sesji z tajnym sekretem po stronie serwera i umieszczane na końcu pliku cookie. Tylko upewnij się, że masz długi sekret. Jeśli chcesz okresowo resetować wszystkie sesje użytkownika, zmień swój sekret.

Aby odpowiedzieć na pytanie, czy chcesz dodać dodatkowy limit czasu do danych sesji może zrobić:

session[:user_id] = user.id 
session[:expires_at] = Time.current + 24.hours 

Potem, gdy uwierzytelnianie użytkowników, wykonaj następujące czynności:

if session[:expires_at] < Time.current 
    # sign out user 
end 

Nadzieja to pomaga.

+4

Pamiętaj, że to rozwiązanie nie działa tak jak jest z Railsami 4.1 i później. Serializator plików cookie domyślnie przyjmuje teraz wartość JSON, więc obiekty czasu są przechowywane jako ciągi. – Chewi

+3

'sesja [: expires_at] .to_time

+0

Prawdopodobnie bardziej typowym zastosowaniem będzie wygaśnięcie sesji po wybranym okresie bezczynności, zamiast nagle znikąd, ponieważ minął pierwotny czas wygasania. Ale wydaje się, że nie jest to (wyraźnie) obejmujące taki przypadek użycia.Umieszczenie drugiego wiersza w wierszu 'before_action' w Kontroli aplikacji, a nie jako część akcji logowania, rozwiązałoby problem. – silverdr

32

Rzeczywiście szyny dziedziczą po Rack::Session::Cookie. Możesz więc skonfigurować parametr expire_after w swoim session_store.rb.

Sqore::Application.config.session_store(
    :cookie_store, 
    key: '_name_session', 
    expire_after: 24.hours 
) 
+1

To jest lepsza odpowiedź i powinna być wybrana. –

+4

Nie, plakat wyraźnie powiedział, że nie chce tego robić, ponieważ może zostać zmieniony po stronie klienta. – Chewi

+0

Świetna odpowiedź. Dokumentacja znajduje się tutaj: http://api.rubyonrails.org/classes/ActionDispatch/Session/CookieStore.html – dontangg

1

dodać do kontrolera aplikacji: before_filter: session_expires,: oprócz => [: logowanie,: wylogowania] before_filter: update_session_time,: oprócz => [: logowanie,: wylogowania]

def session_expires 
@time_left = (session[:expires_at] - Time.now).to_i 
unless @time_left > 0 
reset_session 
flash[:error] = 'Lorem Ipsum.' 
redirect_to :controller => 'foo', :action => 'bar' 
end 
end 

def update_session_time 
    session[:expires_at] = 60.minutes.from_now 
end