Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you use Rails AuthenticityToken infrastructure to explicitly protect a GET action

Rails AuthenticityToken automatically protects POST/PUT/DELETE requests from CSRF attacks. But I have another use case in mind.

I am showing a video on my site that I don't want to be embeddable on other sites. How this works is that my flash player sends a request for a signed URL from my CDN that expires in a few seconds. Up until now a user had to be logged in to watch videos, so that was the authentication. However now I want any visitor to the site to be able to watch the video without allowing the signed URL to be requested from another site (such as if they embedded our player on their site).

My first thought went to AuthenticityToken since it seems to have these exact semantics... all I need to do is plug it into a GET request. Any ideas?

like image 812
gtd Avatar asked Dec 29 '22 09:12

gtd


2 Answers

Rails, opinionated as it is believes that all GET requests should be idempotent. This means Rails of course does not check authenticity tokens for GET requests, even verified_request? gives every GET a pass.

def verified_request?
  !protect_against_forgery?     ||
    request.method == :get      ||
    !verifiable_request_format? ||
    form_authenticity_token == params[request_forgery_protection_token]
end

So we have to write our own logic. We can use form_authenticity token. All this does is create a random string and cache it in the session:

def form_authenticity_token
   session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
end

We can therefore make a before filter that tests the equality of a url parameter to the session token. Thereby ensuring that only bonafide visitors can view videos.

Controller:

class CDNController < ActionController::Base
  # You probably only want to verify the show action
  before_filter :verify_request, :only => 'show'

  # Regular controller actions…

  protected

  def verify_request
    # Correct HTTP response code is 403 forbidden, not 404 not found.
    render(:status => 403) unless form_authenticity_token == params[:token]
  end

end

The view:

<%= video_path(:token => form_authenticity_token) %>
like image 118
Steve Graham Avatar answered Feb 05 '23 08:02

Steve Graham


To plug the authenticity token in your url:

<%= video_path(:token => form_authenticity_token) %>

In your CDN's controller, you could check if the authenticity token is correct with a before_filter:

def verify_token
    render_404 unless form_authenticity_token == params[:token]
end

def render_404
    render :file => "#{RAILS_ROOT}/public/404.html", :status => 404
end
like image 31
agregoire Avatar answered Feb 05 '23 09:02

agregoire