diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb index 8123170533346..9e4eb4cdb5bc6 100644 --- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb @@ -329,7 +329,7 @@ def valid_authenticity_token?(session, encoded_masked_token) # :doc: end begin - masked_token = Base64.strict_decode64(encoded_masked_token) + masked_token = decode_csrf_token(encoded_masked_token) rescue ArgumentError # encoded_masked_token is invalid Base64 return false end @@ -394,7 +394,7 @@ def valid_per_form_csrf_token?(token, session) # :doc: def real_csrf_token(session) # :doc: session[:_csrf_token] ||= SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH) - Base64.strict_decode64(session[:_csrf_token]) + decode_csrf_token(session[:_csrf_token]) end def per_form_csrf_token(session, action_path, method) # :doc: @@ -462,5 +462,11 @@ def normalize_action_path(action_path) # :doc: uri = URI.parse(action_path) uri.path.chomp("/") end + + def decode_csrf_token(encoded_csrf_token) + Base64.strict_decode64(encoded_csrf_token) + rescue ArgumentError + Base64.urlsafe_decode64(encoded_csrf_token) + end end end diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 10de9bcc3e533..ae3af22478285 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -377,6 +377,15 @@ def test_should_allow_post_with_token end end + def test_should_allow_post_with_urlsafe_token_when_migrating + token_length = (ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH * 4.0 / 3).ceil + token_including_url_safe_chars = "-_".ljust(token_length, "A") + session[:_csrf_token] = token_including_url_safe_chars + @controller.stub :form_authenticity_token, token_including_url_safe_chars do + assert_not_blocked { post :index, params: { custom_authenticity_token: token_including_url_safe_chars } } + end + end + def test_should_allow_patch_with_token session[:_csrf_token] = @token @controller.stub :form_authenticity_token, @token do