Trong ứng dụng Rails của chúng tôi, chúng tôi sử dụng protect_from_forgery
để ngăn chặn CSRF. Tuy nhiên, những gì chúng tôi thấy là nếu người dùng truy cập trang đăng nhập và sau đó tắt để pha một tách trà trong khoảng thời gian hết hạn phiên ứng dụng (giả sử 15 phút). Đăng nhập chỉ chuyển hướng trở lại trang đăng nhập bất kể thông tin đăng nhập thành công hay không (Tùy thuộc vào môi trường, chúng tôi gặp lỗi InvalidAuthenticityToken
.) Cố gắng đăng nhập lại hoạt động tốt. Nó chỉ thất bại nếu người dùng đã ở trên trang lâu hơn thời gian phiên.Đường ray protect_from_forgery phá vỡ biểu mẫu đăng nhập nếu không hoạt động
Chúng tôi nghĩ điều này thật kỳ lạ vì chúng tôi chưa đăng nhập ... vì vậy phiên nào sắp hết hạn? và chắc chắn một phiên mới đang được tạo khi đăng nhập ngay cả khi phiên đã được tạo và đã hết hạn. Hóa ra (sau khi đọc điều này: https://nvisium.com/blog/2014/09/10/understanding-protectfromforgery/) bảo vệ CSRF trong Rails thực sự sử dụng một phiên để kiểm tra authenticity_token
là hợp lệ. Vì vậy, về cơ bản mã thông báo sẽ hết hạn khi phiên hết hạn (tùy thuộc vào cài đặt session_store
) và bạn không thể đăng nhập mà không làm mới trang một lần nữa.
Chúng tôi đã giải quyết vấn đề này: skip_before_action :verify_authenticity_token, only: [:create]
trong số SessionsController
nhưng bây giờ điều đó có nghĩa là biểu mẫu đăng nhập của chúng tôi không còn được bảo vệ.
Có các tùy chọn nào khác để khắc phục sự cố này? Hay là giải pháp chúng ta đã sử dụng không an toàn như chúng ta nghĩ? Googling cho thấy dòng mã này được sử dụng rất nhiều lần, nhưng chắc chắn đó là một ý tưởng tồi?
giải pháp khác của chúng tôi là để cho phép các ngoại lệ xảy ra, nhưng xử lý nó một cách duyên dáng với:
rescue_from ActionController::InvalidAuthenticityToken do
@exception = exception.message
render 'errors/500', :status => 500, :layout => 'other'
end
Mặc dù vẫn ghét thực tế người dùng ngồi trên trang đăng nhập lâu hơn thời gian chờ phiên (trong trường hợp này 15 phút) gây ra lỗi!
Tuy nhiên, một giải pháp chúng tôi đã đưa ra là để thiết lập session_store để mãi mãi và sau đó tự hết hạn phiên đăng nhập như thế này:
before_action :session_timeout, if: :current_user
def session_timeout
session[:last_seen_at] ||= Time.now
if session[:last_seen_at] < 15.minutes.ago
reset_session
else
session[:last_seen_at] = Time.now
end
end
Bạn sử dụng loại 'session_store' nào? –