diff options
author | Michael Koziarski <michael@koziarski.com> | 2008-11-20 23:06:19 +0100 |
---|---|---|
committer | Michael Koziarski <michael@koziarski.com> | 2008-11-23 14:28:34 +0100 |
commit | 9fdb15e60f4d4e37916e5354c50d559773bbe014 (patch) | |
tree | 2f1c465eea8f798b0a29470ea3bd1f3ab8302ce0 /actionpack/lib/action_controller | |
parent | ed7549da2899e6eb398c209bb0ac680c8bdb6087 (diff) | |
download | rails-9fdb15e60f4d4e37916e5354c50d559773bbe014.tar.gz rails-9fdb15e60f4d4e37916e5354c50d559773bbe014.tar.bz2 rails-9fdb15e60f4d4e37916e5354c50d559773bbe014.zip |
Change the forgery token implementation to just be a simple random string.
This deprecates the use of :secret and :digest which were only needed when we were hashing session ids.
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r-- | actionpack/lib/action_controller/request_forgery_protection.rb | 46 |
1 files changed, 7 insertions, 39 deletions
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb index 3e0e94a06b..f3e6288c26 100644 --- a/actionpack/lib/action_controller/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/request_forgery_protection.rb @@ -5,8 +5,6 @@ module ActionController #:nodoc: module RequestForgeryProtection def self.included(base) base.class_eval do - class_inheritable_accessor :request_forgery_protection_options - self.request_forgery_protection_options = {} helper_method :form_authenticity_token helper_method :protect_against_forgery? end @@ -14,7 +12,7 @@ module ActionController #:nodoc: end # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current web application, not a - # forged link from another site, is done by embedding a token based on the session (which an attacker wouldn't know) in all + # forged link from another site, is done by embedding a token based on a random string stored in the session (which an attacker wouldn't know) in all # forms and Ajax requests generated by Rails and then verifying the authenticity of that token in the controller. Only # HTML/JavaScript requests are checked, so this will not protect your XML API (presumably you'll have a different authentication # scheme there anyway). Also, GET requests are not protected as these should be idempotent anyway. @@ -57,12 +55,8 @@ module ActionController #:nodoc: # Example: # # class FooController < ApplicationController - # # uses the cookie session store (then you don't need a separate :secret) # protect_from_forgery :except => :index # - # # uses one of the other session stores that uses a session_id value. - # protect_from_forgery :secret => 'my-little-pony', :except => :index - # # # you can disable csrf protection on controller-by-controller basis: # skip_before_filter :verify_authenticity_token # end @@ -70,13 +64,12 @@ module ActionController #:nodoc: # Valid Options: # # * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified. - # * <tt>:secret</tt> - Custom salt used to generate the <tt>form_authenticity_token</tt>. - # Leave this off if you are using the cookie session store. - # * <tt>:digest</tt> - Message digest used for hashing. Defaults to 'SHA1'. def protect_from_forgery(options = {}) self.request_forgery_protection_token ||= :authenticity_token before_filter :verify_authenticity_token, :only => options.delete(:only), :except => options.delete(:except) - request_forgery_protection_options.update(options) + if options[:secret] || options[:digest] + ActiveSupport::Deprecation.warn("protect_from_forgery only takes :only and :except options now. :digest and :secret have no effect", caller) + end end end @@ -90,7 +83,7 @@ module ActionController #:nodoc: # # * is the format restricted? By default, only HTML and AJAX requests are checked. # * is it a GET request? Gets should be safe and idempotent - # * Does the form_authenticity_token match the given _token value from the params? + # * Does the form_authenticity_token match the given token value from the params? def verified_request? !protect_against_forgery? || request.method == :get || @@ -105,34 +98,9 @@ module ActionController #:nodoc: # Sets the token value for the current session. Pass a <tt>:secret</tt> option # in +protect_from_forgery+ to add a custom salt to the hash. def form_authenticity_token - @form_authenticity_token ||= if !session.respond_to?(:session_id) - raise InvalidAuthenticityToken, "Request Forgery Protection requires a valid session. Use #allow_forgery_protection to disable it, or use a valid session." - elsif request_forgery_protection_options[:secret] - authenticity_token_from_session_id - elsif session.respond_to?(:dbman) && session.dbman.respond_to?(:generate_digest) - authenticity_token_from_cookie_session - else - raise InvalidAuthenticityToken, "No :secret given to the #protect_from_forgery call. Set that or use a session store capable of generating its own keys (Cookie Session Store)." - end - end - - # Generates a unique digest using the session_id and the CSRF secret. - def authenticity_token_from_session_id - key = if request_forgery_protection_options[:secret].respond_to?(:call) - request_forgery_protection_options[:secret].call(@session) - else - request_forgery_protection_options[:secret] - end - digest = request_forgery_protection_options[:digest] ||= 'SHA1' - OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(digest), key.to_s, session.session_id.to_s) - end - - # No secret was given, so assume this is a cookie session store. - def authenticity_token_from_cookie_session - session[:csrf_id] ||= CGI::Session.generate_unique_id - session.dbman.generate_digest(session[:csrf_id]) + session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32) end - + def protect_against_forgery? allow_forgery_protection && request_forgery_protection_token end |