ruby-on-railsruby-on-rails-4.2

identical forms return different CSRF behaviours


Two actions of the same class have views which are using the same identical form (it has not been refactored to date). This form appears multiple times to change the value of one attribute. It also feeds both the refreshing of the form via XHR and the input of a subsequent form on the page.

<%= form_for(@push_new, url: confirm_budget_promotions_path, remote: true) do |f| %>
 [...]

both render. But I just noticed now that none of the push_new forms include an authenticity_token. The subsequent form does. The rendered HTML has

<form class="new_pushbudget" id="new_pushbudget" action="/promotions/confirm_budget?municipality_slug=gorizia" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="&#x2713;" />

<form class="new_pushbudget" id="new_pushbudget" action="/promotions/confirm_budget?municipality_slug=gorizia" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="&#x2713;" />

they are calling the same action. While the subsequent form is authenticable:

<form class="new_promotion" id="new_promotion" action="/promotions?municipality_slug=gorizia" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="rWkPuaVzAD5ECAPY6dUJLKw1daj8nGuNhX/G0GhfSrWEkSReGkbGI/SB9pksL5XcpLi50SqJoLxqbw2oknOX8w==" />

In one case, the action runs and returns in its XHR response a replacement form

<form class="new_pushbudget" id="new_pushbudget" action="/promotions/confirm_budget?municipality_slug=gorizia" accept-charset="UTF-8" data-remote="true" method="post"><input name="utf8" type="hidden" value="&#x2713;" />

which, incidentally, also runs.

But the other action will not proceed for lack of authenticity_token.

Started POST "/promotions/confirm_budget?municipality_slug=gorizia" for ::1 at 2020-09-17 16:08:49 +0200
Processing by PromotionsController#confirm_budget as HTML
Parameters: {"utf8"=>"✓", "pushbudget"=>{"shop_id"=>"110", "shop_available"=>"287", "budget"=>"1.4"}, "commit"=>"Invia", "municipality_slug"=>"gorizia"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 4ms (ActiveRecord: 0.0ms)

a) eventhough the form renders data-remote="true" Rails is handling this as HTML.
b) this is utterly unexpected behaviour. Is the XHR call 'binded' to the parent page somehow to skip the authentication process?
c) how can I ensure that the token is present in the form (or ignored, as the page is access controlled upstream) ?


Solution

  • False alarm.

    One form was rendering from a page in cache.

    The second was calling the page live, and the javascript libraries were not being called due to a quirk.

    Once the javascript libraries were accessible

    Processing by PromotionsController#confirm_budget as JS
    

    and no CSRF need be invoked