sessions: fix open redirect in login page.
Fix an open redirect exploit where if you went to <https://danbooru.donmai.us/login?url=//fakebooru.com>, then after you logged in you would be redirected to https://fakebooru.com. This was actually fixed by the upgrade to Rails 7.0. `redirect_to` now raises an `UnsafeRedirectError` on redirect to an offsite URL. Before we tried to prevent offsite redirects by checking that the URL started with a slash, but this was insufficient - it allowed protocol-relative URLs like `//fakebooru.com`. Add a test case for protocol-relative URLs and return a 403 error on an offsite redirect.
This commit is contained in:
@@ -115,7 +115,7 @@ class ApplicationController < ActionController::Base
|
||||
render_error_page(400, exception)
|
||||
when SessionLoader::AuthenticationFailure
|
||||
render_error_page(401, exception, template: "sessions/new")
|
||||
when ActionController::InvalidAuthenticityToken, ActionController::UnpermittedParameters, ActionController::InvalidCrossOriginRequest
|
||||
when ActionController::InvalidAuthenticityToken, ActionController::UnpermittedParameters, ActionController::InvalidCrossOriginRequest, ActionController::Redirecting::UnsafeRedirectError
|
||||
render_error_page(403, exception)
|
||||
when ActiveSupport::MessageVerifier::InvalidSignature, # raised by `find_signed!`
|
||||
User::PrivilegeError,
|
||||
|
||||
@@ -16,9 +16,9 @@ class SessionsController < ApplicationController
|
||||
def create
|
||||
name, password, url = params.fetch(:session, params).slice(:name, :password, :url).values
|
||||
user = SessionLoader.new(request).login(name, password)
|
||||
url ||= posts_path
|
||||
|
||||
if user
|
||||
url = posts_path unless url&.start_with?("/")
|
||||
respond_with(user, location: url)
|
||||
else
|
||||
flash.now[:notice] = "Password was incorrect"
|
||||
|
||||
@@ -43,6 +43,11 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_redirected_to tags_path
|
||||
end
|
||||
|
||||
should "not allow redirects to protocol-relative URLs" do
|
||||
post session_path, params: { name: @user.name, password: "password", url: "//example.com" }
|
||||
assert_response 403
|
||||
end
|
||||
|
||||
should "not allow IP banned users to login" do
|
||||
@ip_ban = create(:ip_ban, category: :full, ip_addr: "1.2.3.4")
|
||||
post session_path, params: { name: @user.name, password: "password" }, headers: { REMOTE_ADDR: "1.2.3.4" }
|
||||
|
||||
Reference in New Issue
Block a user