I take courses on rails 5.x.x and when they used form they add a line for token authentication to protect their site, on the start of the form, like this :
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
But to be on the last version of rails i'm on 6.1.3 version and i don't see anything on the web about that.
So the question is : Did I still need to set this authenticity token anywhere ? if yes, where ? and if no, why ? If you have some links about that for rails 6 I don't say no. Thank's you.
No, you don't need to add it manually, Rails does it for you in each form.
<%= form_with do |form| %>
Form contents
<% end %>
generates
<form accept-charset="UTF-8" action="/" method="post">
<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
Form contents
</form>
You'll notice that the HTML contains an input element with type
hidden. This input is important, because non-GET forms cannot be
successfully submitted without it. The hidden input element with the
name authenticity_token is a security feature of Rails called
cross-site request forgery protection, and form helpers generate it
for every non-GET form (provided that this security feature is
enabled). You can read more about this in the Securing Rails
Applications guide.
https://guides.rubyonrails.org/form_helpers.html
Related
Submitting a form requires a token which the receiving server has named authenticity_token and is expecting a string that is known only to posting and receiving servers:
<input id="authenticity_token" name="authenticity_token" type="hidden" value="ac513de198a9f0536df5003fb5ba3122d1ee53d5" />
that value renders if I call an instance or global variable. However, even though the controller is set with the following filter:
skip_before_action :verify_authenticity_token, only: [:reservation]
whether I try
<%= form_tag('https://test.webten.net/form') do %>
<%= hidden_field_tag :authenticity_token, #ppayment.authenticity_token, id: "authenticity_token" %>
or
<%= tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: #ppayment.authenticity_token) %>
or
<input id="" name="authenticity_token" type="hidden" value="ac513de198a9f0536df5003fb5ba3122d1ee53d5" />
Rails ends up squashing each value with its own session setting value and rendering:
<input type="hidden" name="authenticity_token" id="authenticity_token" value="ydi5En1ywUkN5VsYIBXu6JTbQmXtwxNhpKlyjbbLi3RdvCc+A59EdDZvroGsGFplAAE5ATLcSqw25LVQkyPtKw==">
<input type="hidden" name="authenticity_token" value="ydi5En1ywUkN5VsYIBXu6JTbQmXtwxNhpKlyjbbLi3RdvCc+A59EdDZvroGsGFplAAE5ATLcSqw25LVQkyPtKw==">
<input id="authenticity_token" name="authenticity_token" type="hidden" value="ydi5En1ywUkN5VsYIBXu6JTbQmXtwxNhpKlyjbbLi3RdvCc+A59EdDZvroGsGFplAAE5ATLcSqw25LVQkyPtKw==">
How can rails default behaviour be overridden in this controller action?
You have to override the :authenticity_token argument in the form_tag call to prevent Rails from adding the session's authenticity token by default:
<%= form_tag('https://test.webten.net/form', authenticity_token: 'ac513de198a9f0536df5003fb5ba3122d1ee53d5') do %>
or:
<%= form_tag('https://test.webten.net/form', authenticity_token: false) do %>
<%= hidden_field_tag 'authenticity_token', 'ac513de198a9f0536df5003fb5ba3122d1ee53d5' %>
If that doesn't work, you probably have some JS that overwrites the authenticity token you provided from the one in the META tag. Search for 'csrf-token' in your JS.
See http://guides.rubyonrails.org/form_helpers.html#forms-to-external-resources for more information.
[this answer is complementary to the preceeding one. It solves the issue, but in an inelegant manner]
Various possible avenues of solution appear incomplete / off the mark
form_authenticity_tokenis a view helper that returns the current
session's authenticity token. Too late to act upon that as the
layout may already invoke it
most voted response has a per action method
protect_from_forgery for ignoring it for internal purposes. Still
is too late as session already has issued it
a skip before action is just like the previous solution, too
late, session token is issued
The rails guide is incorrect in stating: authenticity_token:
'external_token'
Aaron Breckenridge's answer provide a clue: "you probably have some JS that overwrites the authenticity token ", supported by this posting. Thus one could search the content of app directory and still not find a JS handler... when jquery-ujs, for example, is gem installed. Based on observed behaviour, it must be getting fired up every time it encounters name='authenticity-token' and sets the value based on the META tag (logical. why have 2 different tokens on same page...) - doing its job properly!
Literally, that token must not be generated upstream. So modifying the layout's header section:
<% unless request.path == "/controller/action" %>
<%= csrf_meta_tags %>
<% end %>
is a working solution. This solution gets pollution-prone for multiple paths. Another requires multiple layout handling... thus, file under 'kludgey'. (willing to entertain better one!)
I have what should be a relatively simple form in Rails that I'm using to send an email for two different previews, a desktop preview and a mobile preview.
<form id="email-form" role="form" action="<%= action_name == 'desktop_preview' ? email_preview_newsletter_path(#newsletter) : email_preview_newsletter_path(#newsletter, mobile: 'true') %>">
<label for="email_address">Email</label>
<input type="email" id="email_address" name="email_address" value="<%= params[:email_address] %>" placeholder="PLEASE ENTER EMAIL">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="submit" value="Send" class="btn btn-primary"></input>
</form>
Right now I have it setup so that both previews get sent to the same endpoint, '/email_preview', but in the case of the mobile_preview I want to pass in a 'mobile' query string so that it ends up looking like this:
'/email_preview?mobile=true'
When I inspect the form on the page everything looks in order, however when it gets passed to the controller the 'mobile' part of the query string disappears and only the 'email_address' exists.
I suppose I could pass in the mobile value as a hidden field, but something about that just doesn't feel right to me. What is the best way to setup this form so that both the 'mobile' and 'email_address' key value pairs are passed as query strings when sent to the controller?
In the process of writing out this question I realized exactly what the problem was:
I had the form setup as a GET request as opposed to a POST request.
This was causing any pre-established query strings to get erased in the process of setting up the GET params being defined in the form (in this case, the 'email_address' param). Changing the form from GET to POST, (i.e. form method="POST")
Took care of this issue. Please note that if you are going to manually setup a form like this in rails then you also need to explicitly take care of the csrf token. This can be done by inserting the following input with the helper method into your form:
input type="hidden" name="authenticity_token" value="<%=form_authenticity_token%>"
On a particular page in my website, there are a variety of potential URL parameters:
http://www.example.com/my_webpage?at=2014-01-01&page=5
Now I want a simple way to add a parameter to that like this:
http://www.example.com/my_webpage?at=2014-01-01&page=5&records=100
So I tried the following HTML with embedded Ruby:
<form action="<%= request.original_url %>" method="get"># of records <input type="text" name="records"/></form>
The problem is the resulting page that opens is:
http://www.example.com/my_webpage?records=100
Essentially, the old parameters get wiped away. What's an easy way to retain them? I could loop through the params hash and add hidden_tags (I'd have to selectively exclude params not part of the request params), but I would expect with such a common use case scenario there's a better easier way.
While there isn't an easy Rails way of doing this automatically, Rails does provide access to the request parameters through the request.query_parameters hash. So I simply needed to add this in the form:
<% request.query_parameters.each do |key, val|%>
<input type="hidden" name="<%= key %>" value="<%= val %>"/>
<% end %>
when I submit one page to another, the sites shows the information!
Someone told me to use post to avoid it. however, when I use post method it doesn't work.
<form action="\look\at", method="post">
Select your new car's color.
<br>
<input type="radio" name="radios1" value="red">red
<input type="radio" name="radios1" value="green">green
<input type="radio" name="radios1" value="blue">blue
<br>
<br>
<input type="submit"/>
</form>
When I submit I can not see \look\at page. but I delete method="post" It works well.
How I use post method?
Check your routes (in config/routes.rb).
Probably you will have a line
get '/look/at', to: 'look#at'
replace get by post and it will accept a post.
Since you are not using the rails form helper or view mechanism (erb/haml) (please start using them, why write plain html????), you have to skip the authenticity token check (please note that this check is there for a reason: it is a protection against cross-site request forgery).
Just add the following line at the top of your controller:
skip_before_filter :verify_authenticity_token
After the user has logged in and their username authenticated and saved in session[:user_name], when submitting a form with method="post" (using standard html) all session data is cleared and user is routed back to the login page. This does not happen if the method is set to get.
Post works when I use the rails "form_tag" which generates these additional lines:
<div style="margin: 0pt; padding: 0pt; display: inline;">
<input type="hidden" value="✓" name="utf8">
<input type="hidden" value="a_bunch_of_gibberish" name="authenticity_token">
</div>
What is happening?
Are you using Rails 3.0.4? It sounds like it might be related to the CSRF fix.
If you need a fix specific to your needs, you can overwrite #handle_unverified_request in your controller. See https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/request_forgery_protection.rb.
Here's an example where this issue was with OmniAuth and OpenId. (See section 'CSRF Protection In Rails 3.0.4')
This issue can also happen if you're creating your own html form.
If you're getting redirected without knowing why, it's because of "protect_from_forgery" in your ApplicationController
In order to allow your form to post, add the following code to it (or use form_tag, explanation below):
<form ... >
...
<%= hidden_field_tag "authenticity_token", form_authenticity_token %>
...
</form>
The reason the "form_tag" works is because form_tag generates the hidden field for you =)