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开发者_JAVA百科 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?
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) %>
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
精彩评论