controllers: don't allow GET requests with params in the body.

Don't allow GET requests to pass the request params in the body instead
of in the URL. While Rails can handle GET params passed in the body, it
goes against spec and it may cause problems if the response is a redirect
and the client doesn't send the body params when following the redirect.

This may be a breaking change for broken API clients who were sending
GET params in the body instead of in the URL. This can happen when people
use HTTP libraries incorrectly.
This commit is contained in:
evazion
2022-09-19 15:59:30 -05:00
parent 7977572865
commit 3184e77de0
2 changed files with 22 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
class ApplicationController < ActionController::Base
class PageRemovedError < StandardError; end
class RequestBodyNotAllowedError < StandardError; end
include Pundit::Authorization
helper_method :search_params, :permitted_attributes
@@ -9,6 +10,7 @@ class ApplicationController < ActionController::Base
self.responder = ApplicationResponder
skip_forgery_protection if: -> { SessionLoader.new(request).has_api_authentication? }
before_action :check_get_body
before_action :reset_current_user
before_action :set_current_user
before_action :normalize_search
@@ -120,6 +122,8 @@ class ApplicationController < ActionController::Base
render_error_page(401, exception, message: exception.message, template: "sessions/new")
when ActionController::InvalidAuthenticityToken, ActionController::UnpermittedParameters, ActionController::InvalidCrossOriginRequest, ActionController::Redirecting::UnsafeRedirectError
render_error_page(403, exception, message: exception.message)
when RequestBodyNotAllowedError
render_error_page(403, exception, message: "Request body not allowed for #{request.method} request")
when ActiveSupport::MessageVerifier::InvalidSignature, # raised by `find_signed!`
User::PrivilegeError,
Pundit::NotAuthorizedError
@@ -193,6 +197,10 @@ class ApplicationController < ActionController::Base
request.variant = params[:variant].try(:to_sym)
end
def check_get_body
raise RequestBodyNotAllowedError if request.method.in?(%w[GET HEAD OPTIONS]) && request.body.size > 0
end
# allow api clients to force errors for testing purposes.
def cause_error
return unless params[:cause_error].present?