Skip to content

Commit 731a664

Browse files
Merge pull request from GHSA-xm34-v85h-9pg2
Fix account takeover through CSRF attack
2 parents ed42532 + ec4fbe6 commit 731a664

2 files changed

Lines changed: 48 additions & 1 deletion

File tree

lib/controllers/frontend/spree/users_controller.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
class Spree::UsersController < Spree::StoreController
44
skip_before_action :set_current_order, only: :show, raise: false
5-
prepend_before_action :load_object, only: [:show, :edit, :update]
65
prepend_before_action :authorize_actions, only: :new
76

87
def show
8+
load_object
99
@orders = @user.orders.complete.order('completed_at desc')
1010
end
1111

@@ -23,7 +23,12 @@ def create
2323
end
2424
end
2525

26+
def edit
27+
load_object
28+
end
29+
2630
def update
31+
load_object
2732
if @user.update(user_params)
2833
spree_current_user.reload
2934
redirect_url = spree.account_url
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.feature 'User update', type: :request do
4+
context 'CSRF protection' do
5+
%i[exception reset_session null_session].each do |strategy|
6+
# Completely clean the configuration of forgery protection for the
7+
# controller and reset it after the expectations. However, besides `:with`,
8+
# the options given to `protect_from_forgery` are processed on the fly.
9+
# I.e., there's no way to retain them. The initial setup corresponds to the
10+
# dummy application, which uses the default Rails skeleton in that regard.
11+
# So, if at some point Rails changed the given options, we should update it
12+
# here.
13+
around do |example|
14+
controller = Spree::UsersController
15+
old_allow_forgery_protection_value = controller.allow_forgery_protection
16+
old_forgery_protection_strategy = controller.forgery_protection_strategy
17+
controller.skip_forgery_protection
18+
controller.allow_forgery_protection = true
19+
controller.protect_from_forgery with: strategy
20+
21+
example.run
22+
23+
controller.allow_forgery_protection = old_allow_forgery_protection_value
24+
controller.forgery_protection_strategy = old_forgery_protection_strategy
25+
end
26+
27+
it "is not possible to take account over with the #{strategy} forgery protection strategy" do
28+
user = create(:user, email: 'legit@mail.com', password: 'password')
29+
30+
post '/login', params: "spree_user[email]=legit@mail.com&spree_user[password]=password"
31+
begin
32+
put '/users/123456', params: 'user[email]=hacked@example.com'
33+
rescue
34+
# testing that the account is not compromised regardless of any raised
35+
# exception
36+
end
37+
38+
expect(user.reload.email).to eq('legit@mail.com')
39+
end
40+
end
41+
end
42+
end

0 commit comments

Comments
 (0)