rubysinatracsrf

How can I make Sinatra use CSRF Authenticity tokens?


I'm building a simple app in ruby using the Sinatra framework. It's mainly "get" based - most requests will be for listing data. However there are a couple of key screens in the app that will collect user input. I want to ensure the app is as safe as I can make it, and currently, trying to find how to implement the kind of authenticity tokens that you get in a Rails form?

Where I've got to: Well, I know I need the tokens for csrf, but I'm unsure if I need to generate them myself or if Sinatra can do it for me - I've looked through the docs and they say that Sinatra is using Rack Protection, however, I can't find any example code for it and can't seem to figure out how to get it going - any help apprectiated - thanks!


Solution

  • Use the rack_csrf gem. Install it with

    gem install rack_csrf
    

    The rack_csrf gem has a Sinatra example. Below is a simpler example adapted from this page (seems offline. Archived version):

    require "rack/csrf"
    
    configure do
      use Rack::Session::Cookie, :secret => "some unique secret string here"
      use Rack::Csrf, :raise => true
    end
    

    Using enable :sessions instead of use Rack::Session::Cookie ... will also work in most cases (see Bill's comment).

    In your view, you can get the token (or the tag) with the Rack::Csrf.csrf_token and Rack::Csrf.csrf_tag methods. If this appears lengthy, you may want to define a helper along the lines of:

    helpers do
      def csrf_token
        Rack::Csrf.csrf_token(env)
      end
    
      def csrf_tag
        Rack::Csrf.csrf_tag(env)
      end
    end
    

    Small example using the helper method:

    <form method="post" action="/tweet">
      <%= csrf_tag %>
      <input type="text" name="message"/>
      <input type="submit" value="Submit a tweet!"/>
    </form>