69

I'm a PHP developer learning Ruby on Rails by reading Michael Hartl's tutorial. Here is a quote from the book, referring to csrf_meta_tag:

...the Rails method csrf_meta_tag [prevents] cross-site request forgery (CSRF), a type of malicious web attack. Don’t worry about the details (I don’t); just know that Rails is working hard to keep your application secure.

The thing is, I'm genuinely curious. How does inserting csrf-param and csrf-token meta tags prevent CSRF? I tried Googling, but couldn't find anything.

Oxfist
  • 613
  • 5
  • 18
Nick
  • 7,291
  • 15
  • 58
  • 103
  • 6
    @MikhailNikalyukin Thanks (I think). That explains CSRF, which I already knew the basics of, but it doesn't explain how *meta tags* (as opposed to hidden form fields) can prevent it. Do you know the answer to that? – Nick Apr 03 '12 at 15:54

5 Answers5

78

csrf_meta_tag is basically fulfilling the same thing as hidden form fields but is there to give javascript requests that aren't tied to a form an easy way of getting the token.

If you use the jquery-ujs library the content of that meta tag is automatically added (as a request header) to any ajax requests made.

Frederick Cheung
  • 79,397
  • 6
  • 137
  • 164
  • Short and sweet. You answered my question. Thanks! – Nick Aug 18 '12 at 05:46
  • Just to complete: [this article](http://robots.thoughtbot.com/a-tour-of-rails-jquery-ujs) mentions that ujs can also use them to update outdated fragment caches. [Relevant uJS source line](https://github.com/rails/jquery-ujs/blob/57f4848652584f33018e46414605a873194a97d7/src/rails.js#L57). And just in case there a newbs like me wondering: `form_tag` and other helpers also add the CSRF token to the form, so they work without Js. – Ciro Santilli新疆棉花TRUMP BAN BAD Nov 12 '14 at 21:11
58

The csrf_meta_tag inserts what is essentially a digitial signature into the page, acting as verification that requests coming into the application server are, in fact, from properly logged in users. This helps prevent cross-site scripting (a script on a completely unrelated page firing requests off to say, GMail, while you're logged into your GMail in another tab).

I guess to clarify, the csrf_meta_tag itself doesn't prevent an unrelated page from firing off requests to your GMail (or any other service that is the target of the attack), but the "digital signature" in the csrf_meta_tag is used to verify the validity of said requests. Invalid requests (i.e. from cross-site scripting attempts) should fail validation, and are therefore discarded.

To say it another way, from the attacker's point of view:

Before csrf_meta_tags existed (they aren't exclusive to Rails by any means), successful cross-site scripting attacks allowed a malicious site to submit data to a web app in a way that makes the request appear as if it's being done on the user's behalf. So, let's say you're an admin on a web service, and in one browser tab you're logged into the admin panel for that service. If a malicious site open in another tab targeted your service for an attack, the malicious site might be able to run scripts that make admin requests, such as dumping list of users from the database, stealing other sensitive data, or potentially harming, damaging, or destroying data contained in the service, all while appearing (from the server's standpoint) to be valid requests from the admin themselves. The csrf_meta_tag is a way to sign requests, and help thwart such attempts from being successful.

There's a much more detailed explanation available here.

It would also be educational to do a "view source" on one of your Rails-generated pages, and you'll see what the CSRF tag looks like.

jefflunt
  • 32,075
  • 7
  • 80
  • 122
  • 2
    Thanks for the detailed answer! Although it was helpful and I was able to learn from it, it didn't explain how *meta tags* help with CSRF prevention (as opposed to, say, hidden form fields). But I truly appreciate your time. Thanks again! – Nick Aug 18 '12 at 05:45
14

In Rails it will work like this way

def csrf_meta_tags
    if protect_against_forgery?
      [
        tag('meta', :name => 'csrf-param', :content => request_forgery_protection_token),
        tag('meta', :name => 'csrf-token', :content => form_authenticity_token)
      ].join("\n").html_safe
    end
  end

See more details just click

You also need to check Ruby On Rails Security Guide

here is the nice blog

BUT - I prefere National Vulnerability Database, here is the good explanation

CWE-352: Cross-Site Request Forgery (CSRF)

CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

Check this document for CWE - Common Weakness Enumeration

AMIC MING
  • 6,130
  • 6
  • 44
  • 61
  • 1
    Great links to the vulnerability database! – jefflunt Apr 03 '12 at 19:06
  • 2
    Thanks for the detailed answer! Although it was helpful and I was able to learn from it, it didn't explain how *meta tags* help with CSRF prevention (as opposed to, say, hidden form fields). The link to the source code explained that a little, though. Anyway, I truly appreciate your time. Thanks again! – Nick Aug 18 '12 at 05:46
  • Hi Nick, I have direction of the question, I will change my answer very soon and update you. Mostly in this weekend. – AMIC MING Aug 21 '12 at 18:35
4

csrf_meta_tags are indications for ajax requests to use these as one of the form parameters to make a request to the server. Rails expects the csrf as part of your form body (params) to process your requests. Using these meta tags you can construct the form body or the csrf header to suit your needs. I hope this answer helps your question.

Arslan Ali
  • 16,294
  • 7
  • 51
  • 65
praveenag
  • 145
  • 1
  • 9
1

Output of the helper csrf_meta_tags:

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="J/gw2ePXHS9Z1SUSSeUQgMmPhsPEFlFbMrLTLFHLfKjeWh7g4uyOnBlfKnlZlmCBiALDWdDWCSo1z0tybGVtfA==" />

This token can be included in ajax request. Exapmle (jquery-ujs):

https://github.com/rails/jquery-ujs/blob/4b6e30f68ff1244fc0c790641d3408c2695a29bd/src/rails.js#L70

    csrfToken: function() {
     return $('meta[name=csrf-token]').attr('content');
    },

    // URL param that must contain the CSRF token
    csrfParam: function() {
     return $('meta[name=csrf-param]').attr('content');
    },

    // Make sure that every Ajax request sends the CSRF token
    CSRFProtection: function(xhr) {
      var token = rails.csrfToken();
      if (token) xhr.setRequestHeader('X-CSRF-Token', token);
    },
artamonovdev
  • 3,758
  • 1
  • 23
  • 32