autocomplete: don't send cookies in publicly cached responses.

Fix session cookies being sent in publicly cached /autocomplete.json
responses. We can't set any cookies in a response that is being publicly
cached, otherwise they'll be visible to other users. If a user's session
cookies were to be cached, then it would allow their account to be stolen.

In reality, well-behaved caches like Cloudflare will simply refuse to
cache responses that contain cookies to avoid this scenario.

https://support.cloudflare.com/hc/en-us/articles/200172516-Understanding-Cloudflare-s-CDN:

    BYPASS is returned when enabling Origin Cache-Control. Cloudflare also
    sets BYPASS when your origin web server sends cookies in the response
    header.
This commit is contained in:
evazion
2020-12-15 03:43:13 -06:00
parent 26246b0ac9
commit c836c93b81
2 changed files with 17 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base
before_action :set_variant
before_action :add_headers
before_action :cause_error
after_action :skip_session_if_publicly_cached
after_action :reset_current_user
layout "default"
@@ -148,6 +149,14 @@ class ApplicationController < ActionController::Base
CurrentUser.root_url = root_url.chomp("/")
end
# Skip setting the session cookie if the response is being publicly cached to
# prevent the user's session cookie from being leaked to other users.
def skip_session_if_publicly_cached
if response.cache_control[:public] == true
request.session_options[:skip] = true
end
end
def set_variant
request.variant = params[:variant].try(:to_sym)
end

View File

@@ -34,6 +34,14 @@ class AutocompleteControllerTest < ActionDispatch::IntegrationTest
assert_autocomplete_equals(["rating:safe"], "rating:s", "tag_query")
assert_autocomplete_equals(["rating:safe"], "-rating:s", "tag_query")
end
should "not set session cookies when the response is publicly cached" do
get autocomplete_index_path(search: { query: "azur", type: "tag_query" }), as: :json
assert_response :success
assert_equal(true, response.cache_control[:public])
assert_equal({}, response.cookies)
end
end
end
end