Merge branch 'fix/control-headers' into 'master'
[master] Resolve "Sensitive information is stored in browser history" See merge request gitlab/gitlabhq!2555
This commit is contained in:
commit
f0b3edf2ca
4 changed files with 69 additions and 7 deletions
|
@ -46,6 +46,8 @@ class ApplicationController < ActionController::Base
|
|||
:git_import_enabled?, :gitlab_project_import_enabled?,
|
||||
:manifest_import_enabled?
|
||||
|
||||
DEFAULT_GITLAB_CACHE_CONTROL = "#{ActionDispatch::Http::Cache::Response::DEFAULT_CACHE_CONTROL}, no-store".freeze
|
||||
|
||||
rescue_from Encoding::CompatibilityError do |exception|
|
||||
log_exception(exception)
|
||||
render "errors/encoding", layout: "errors", status: 500
|
||||
|
@ -244,6 +246,13 @@ class ApplicationController < ActionController::Base
|
|||
headers['X-XSS-Protection'] = '1; mode=block'
|
||||
headers['X-UA-Compatible'] = 'IE=edge'
|
||||
headers['X-Content-Type-Options'] = 'nosniff'
|
||||
|
||||
if current_user
|
||||
# Adds `no-store` to the DEFAULT_CACHE_CONTROL, to prevent security
|
||||
# concerns due to caching private data.
|
||||
headers['Cache-Control'] = DEFAULT_GITLAB_CACHE_CONTROL
|
||||
headers["Pragma"] = "no-cache" # HTTP 1.0 compatibility
|
||||
end
|
||||
end
|
||||
|
||||
def validate_user_service_ticket!
|
||||
|
|
|
@ -792,4 +792,30 @@ describe ApplicationController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'control headers' do
|
||||
controller(described_class) do
|
||||
def index
|
||||
render json: :ok
|
||||
end
|
||||
end
|
||||
|
||||
context 'user not logged in' do
|
||||
it 'sets the default headers' do
|
||||
get :index
|
||||
|
||||
expect(response.headers['Cache-Control']).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'user logged in' do
|
||||
it 'sets the default headers' do
|
||||
sign_in(user)
|
||||
|
||||
get :index
|
||||
|
||||
expect(response.headers['Cache-Control']).to eq 'max-age=0, private, must-revalidate, no-store'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,17 @@ shared_examples 'content not cached without revalidation' do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'content not cached without revalidation and no-store' do
|
||||
it 'ensures content will not be cached without revalidation' do
|
||||
# Fixed in newer versions of ActivePack, it will only output a single `private`.
|
||||
if Gitlab.rails5?
|
||||
expect(subject['Cache-Control']).to eq('max-age=0, private, must-revalidate, no-store')
|
||||
else
|
||||
expect(subject['Cache-Control']).to eq('max-age=0, private, must-revalidate, private, no-store')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe UploadsController do
|
||||
let!(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
|
||||
|
||||
|
@ -177,7 +188,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png'
|
||||
|
||||
|
@ -239,7 +250,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png'
|
||||
|
||||
|
@ -292,7 +303,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png'
|
||||
|
||||
|
@ -344,7 +355,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png'
|
||||
|
||||
|
@ -388,7 +399,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png'
|
||||
|
||||
|
@ -445,7 +456,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png'
|
||||
|
||||
|
@ -498,7 +509,7 @@ describe UploadsController do
|
|||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
it_behaves_like 'content not cached without revalidation' do
|
||||
it_behaves_like 'content not cached without revalidation and no-store' do
|
||||
subject do
|
||||
get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png'
|
||||
|
||||
|
|
|
@ -322,6 +322,22 @@ describe 'Project' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'content is not cached after signing out', :js do
|
||||
let(:user) { create(:user, project_view: 'activity') }
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
it 'does not load activity', :js do
|
||||
project.add_maintainer(user)
|
||||
sign_in(user)
|
||||
visit project_path(project)
|
||||
sign_out(user)
|
||||
|
||||
page.evaluate_script('window.history.back()')
|
||||
|
||||
expect(page).not_to have_selector('.event-item')
|
||||
end
|
||||
end
|
||||
|
||||
def remove_with_confirm(button_text, confirm_with)
|
||||
click_button button_text
|
||||
fill_in 'confirm_name_input', with: confirm_with
|
||||
|
|
Loading…
Reference in a new issue