Why Rails puts csrf token like this - ruby-on-rails

I've never used Rails (that only could answer my question), but I see it puts CSRF tokens in each page with forms.
What I don't understand is why it uses two meta tags for that:
<meta name="csrf-token" content="<%= form_authenticity_token %>" />
<meta name="csrf-param" content="authenticity_token" />
Why not just the csrf-token meta?
<meta name="csrf-token" content="<%= form_authenticity_token %>" />
What's the use of csrf-param?

Rails allows you to do a lot of configuration under the hood related to the CSRF token. If you like, you can change the name of the param -- but if you do, the jQuery UJS driver needs to know the name of the new parameter (since it's used in Ajax requests). That's why there are two meta params here: the first is the actual authenticity token, obviously, but the second is required by Rails' JavaScript drivers in order to even know the name of the first one. (You can see this in action in the jQuery driver or the Prototype driver.)
You could argue this gets you into some kind of crazy loop -- why can't you rename the csrf-param meta tag with another meta tag? I think this was done to allow Rails to easily adopt existing CSRF solutions without needing a lot of manual overrides. Also it allows your apps to be slightly future-proofed. If the HTML5 standard ever adopts an official tag for CSRF tokens, and Rails opts to change the default CSRF tag in a future version, the JavaScript drivers won't have to change at all.
Ultimately, I think that's closest to the real reason this exists: it's insurance against future changes in the CSRF system, preventing unnecessary and possibly extremely annoying deprecations down the road.

csrf-param contains the name of the parameter and csrf-token is the value of the parameter.
So, your form would look like this :
<form action="/" method="post">
<input type="hidden" name="authenticity_token" value="OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjkGTfMTVi
MGYwMGEwOA==">
…
</form>

Related

Sometimes can't verify CSRF token authenticity in regular web app

I have a simple Rails 6 app where I use a form
<%= bootstrap_form_with(model: event, local: true, html: { multipart: true }) do |form| %>
In the generated HTML I have this is the header
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="SOME TOKEN" />
And in the form
<input type="hidden" name="authenticity_token" value="SOME OTHER TOKEN" />
Usually all works fine, but sometimes I get an error
Can't verify CSRF token authenticity.
The log shows be that the token has been passed in the parameters and I cannot find out why the validation fails. I ma sure that there is no malicious use or anything like that.
Are there any reasons why a CSRF token loses its validity? Maybe it's only valid for a certain time?
CSRF protection in Rails works by storing a random value as a field in the form being submitted, and also in the user session. If the values don't match when a form is submitted, Rails rejects the form submission request.
If you're using the default cookie session store in Rails, then
sessions won't expire (until the cookie does). If you're using
something else (file or DB backed sessions), then yes, if those
sessions expire, the form submission will fail with a CSRF error.
So if you're using cookie based sessions (the default), check the cookie expiry. If that looks OK, it's probably some other issue.

Rails 4 authenticity token - both in header and form hidden input?

I'm attempting to get full page caching in Rails but I've hit a big of a snag with regards to CSRF - or perhaps just my understanding of it. I currently have the form_authenticity_token string stored in a cookie that JS can access and rewrite the header tags with.
There are two places I find tokens in my generated HTML:
1) In the head
<meta name="csrf-token" content="[hash]">
2) Inside a form's hidden input element
<input type="hidden" name="authenticity_token" value="[different hash]">
As indicated, these hashes are different from one another (in development mode where caching isn't enabled). Why are they different? Why is it that I can delete the head meta tags and leave the form input alone and the request is allowed? Yet when I delete the form input tag and leave the headers the request is rejected?
Effectively this means the head tags are useless, no? I can rewrite the form input tag to the value in my cookie just like I did with the header tags, but since they are different from one another I'm cautious as to what the end result might mean especially when it comes to full page caching.
Application Controller contains:
protect_from_forgery with: :exception
before_filter :csrf_cookie
def csrf_cookie
cookies['authenticity-token'.freeze] = {
value: form_authenticity_token,
expires: 1.day.from_now,
secure: (Rails.env.staging? || Rails.env.production?)
}
end
Browsing SO on another issue led me to the answer. In short, Rails helps out jQuery users by inserting the CSRF token into ajax requests automatically. It looks for it in the meta tags.
So having the CSRF token inside the form is useful for when submitting POST requests and having it in the head is useful for saving time/effort/mistakes with ajax requests.
Perhaps it's good to have it in both also because you may want to do an ajax request when there isn't a form present. If there IS a form and javascript is disabled, having it in the header doesn't do anyone any favours as it won't be included in the POST request.
As to why they are different, I can only guess it has something to do with the algorithm at the time of generation...but that's neither here nor there as both tokens work.

Open Search Server: Connect custom html meta tags to schema fields

I've set up a new OSS to handle search on a forum. The basic setup was rather straight forward but upon tweaking it I've gotten stuck. The issue is that the pages have a custom meta tag like this:
<meta name="searchtype" content="construction_collection" />
I have set up a field in my Schema with the same name and then added it to the returned fields in the query. However that tag in the result xml is always empty:
<result name="response" numFound="173" collapsedDocCount="0" start="0" rows="10" maxScore="2357,006" time="6">
<doc score="2357,006" pos="0" docId="4008">
<field name="searchtype"/>
and I fail to comprehend how to setup the Parser and Crawler in order to connect these. Some threads here insinuate that it should work automatically, but it doesn't. Surely I need to set up something more. What have I missed?
/Simon
By default, the HTML parser of OpenSearchServer try to extract only the visible information of the Web page.
It is possible to retrieve information stored in meta only if they use a specific syntax. Your meta should be in the form:
<meta name="opensearchserver.field.searchtype" content="contruction_collection" />
You can also populate several fields:
<meta name="opensearchserver.field.searchtype.anotherfield" content="contruction_collection" />

W3C validator shows new error: "Meta requires 'name' attribute"

The w3C validator was all fine with this code:
<meta property="og:site_name" content="--Sitename--" />
If I replace the property attribute with name, the validator says og:site_name is not registered.
All of a sudden today it displayed this error:
Error Line 7, Column 66: Element meta is missing required attribute name.
Nothing is changed but this error popped up.
Anyone knows why, and the solution for that?
For HTML5
If a meta element has the property attribute (from RDFa), the name attribute is not required.
See the section "Extensions to the HTML5 Syntax" from the W3C Recommendation HTML+RDFa 1.1 - Second Edition:
If the RDFa #property attribute is present on the meta element, neither the #name, #http-equiv, nor #charset attributes are required and the #content attribute MUST be specified.
So your markup is fine:
<meta property="og:site_name" content="--Sitename--" />
But it’s (now) even valid if you use the name attribute instead of RDFa’s property, because the OGP values are registered. So this is fine, too:
<meta name="og:site_name" content="--Sitename--" />
And you could even combine both ways:
<meta name="og:site_name" property="og:site_name" content="--Sitename--" />
It's hard to get what validator and in what mode you're using. Suppose it's validator.w3.org. Than notice that HTML5 support there is "experimental". And "property" tags refer to rdfa which is part of HTML5 standard. To dive in further details one need your code snippet or page url...
I had the same problem which I find really borring.
This might not be the answer you were waiting for but I recommend using http://validator.nu/ instead of W3C validator.

Href not working in GSP pages

I am using modal box plugin with grails. The problem is that the link that it creates does not always call the server side code.
here is the link on the page
<modalbox:createLink
controller="company"
action="setChangeCompanyAdmin"
absolute="true"
mapping="changeAdmin"
id="${companyInstance.id}"
title="Change Primary Admin"
width="600"
linkname="Change Primary Admin" />
The action in the controller is preparing a list in the certain way to be displayed in the popup that the modal box opens. But the problem is that the server side is not being called every time, only in IE.
I have tried absolute and specifying a mapping as well but to no avail.
Also i have set the page attributes in the gsp page to not cache the data at all.
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
But even this does not seem to work.
Any help is much appreciated.
Adhir
The browser is still caching your request. You can add a parameter of the current time stamp to the request.
<modalbox:createLink
controller="company"
action="setChangeCompanyAdmin"
absolute="true"
params="${cacheKiller: new Date()​.time​}"
mapping="changeAdmin"
id="${companyInstance.id}"
title="Change Primary Admin"
width="600"
linkname="Change Primary Admin" />
It is probably IE caching the response. If you want to disable caching via the controller's response object, the following code should work:
response.setHeader("Pragma", "no-cache")
response.setHeader("Cache-Control", "no-cache, no-store")

Resources