Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 7592

Show
Ignore:
Timestamp:
09/23/07 02:32:55 (8 months ago)
Author:
rick
Message:

Merge csrf_killer plugin into rails. Adds RequestForgeryProtection model that verifies session-specific _tokens for non-GET requests. [Rick]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r7589 r7592  
    11*SVN* 
     2 
     3* Merge csrf_killer plugin into rails.  Adds RequestForgeryProtection model that verifies session-specific _tokens for non-GET requests.  [Rick] 
    24 
    35* Secure #sanitize, #strip_tags, and #strip_links helpers against xss attacks.  Closes #8877. [Rick, lifofifo, Jacques Distler] 
  • trunk/actionpack/lib/action_controller.rb

    r7450 r7592  
    5555require 'action_controller/components' 
    5656require 'action_controller/record_identifier' 
     57require 'action_controller/request_forgery_protection' 
    5758 
    5859require 'action_view' 
     
    7576  include ActionController::Components 
    7677  include ActionController::RecordIdentifier 
     78  include ActionController::RequestForgeryProtection 
    7779end 
  • trunk/actionpack/lib/action_controller/base.rb

    r7520 r7592  
    327327    @@resource_action_separator = "/" 
    328328    cattr_accessor :resource_action_separator 
     329     
     330    # Sets the token parameter name for RequestForgery.  Calling #verify_token sets it to :_token by default 
     331    @@request_forgery_protection_token = nil 
     332    cattr_accessor :request_forgery_protection_token 
    329333 
    330334    # Holds the request object that's primarily used to get environment variables through access like 
  • trunk/actionpack/lib/action_controller/rescue.rb

    r7438 r7592  
    2121      'ActiveRecord::RecordNotSaved'       => :unprocessable_entity, 
    2222      'ActionController::MethodNotAllowed' => :method_not_allowed, 
    23       'ActionController::NotImplemented'   => :not_implemented 
     23      'ActionController::NotImplemented'   => :not_implemented, 
     24      'ActionController::InvalidToken'     => :unprocessable_entity 
    2425    } 
    2526 
  • trunk/actionpack/lib/action_view/base.rb

    r7589 r7592  
    329329    end 
    330330 
     331    delegate :request_forgery_protection_token, :to => :controller 
     332 
    331333    @@template_handlers = HashWithIndifferentAccess.new 
    332334  
  • trunk/actionpack/lib/action_view/helpers/form_tag_helper.rb

    r7423 r7592  
    402402            when /^post$/i, "", nil 
    403403              html_options["method"] = "post" 
    404               '' 
     404              request_forgery_protection_token ? content_tag(:div, token_tag, :style => 'margin:0;padding:0') : '' 
    405405            else 
    406406              html_options["method"] = "post" 
    407               content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method), :style => 'margin:0;padding:0') 
     407              content_tag(:div, tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag, :style => 'margin:0;padding:0') 
    408408          end 
    409409        end 
     
    420420          concat("</form>", block.binding) 
    421421        end 
     422 
     423        def token_tag 
     424          if request_forgery_protection_token.nil? 
     425            '' 
     426          else 
     427            tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_token) 
     428          end 
     429        end 
    422430    end 
    423431  end 
  • trunk/actionpack/lib/action_view/helpers/prototype_helper.rb

    r7468 r7592  
    739739          js_options['parameters'] = options[:with] 
    740740        end 
     741         
     742        if request_forgery_protection_token 
     743          if js_options['parameters'] 
     744            js_options['parameters'] << " + '&" 
     745          else 
     746            js_options['parameters'] = "'" 
     747          end 
     748          js_options['parameters'] << "_token=' + encodeURIComponent('#{escape_javascript form_token}')" 
     749        end 
    741750       
    742751        options_for_javascript(js_options) 
  • trunk/actionpack/lib/action_view/helpers/text_helper.rb

    r7589 r7592  
    326326      #   # => Blog: Visit 
    327327      def strip_links(html) 
    328         # Stupid firefox treats '<href="http://whatever.com" onClick="alert()">something' as link!  
    329         if html.index("<a") || html.index("<href")    
    330           tokenizer = HTML::Tokenizer.new(html)  
    331           result = '' 
    332           while token = tokenizer.next  
    333             node = HTML::Node.parse(nil, 0, 0, token, false)  
    334             result << node.to_s unless node.is_a?(HTML::Tag) && ["a", "href"].include?(node.name)  
    335           end  
    336           strip_links(result) # Recurse - handle all dirty nested links 
     328        if !html.blank? && html.index("<a") || html.index("<href") 
     329          tokenizer = HTML::Tokenizer.new(html) 
     330          result = returning [] do |result| 
     331            while token = tokenizer.next  
     332              node = HTML::Node.parse(nil, 0, 0, token, false)  
     333              result << node.to_s unless node.is_a?(HTML::Tag) && ["a", "href"].include?(node.name)  
     334            end  
     335          end 
     336          strip_links(result.join) # Recurse - handle all dirty nested links 
    337337        else 
    338338          html 
     
    442442      # 
    443443      # ==== Examples 
     444      # 
    444445      #   strip_tags("Strip <i>these</i> tags!") 
    445446      #   # => Strip these tags! 
     
    451452      #   # => Welcome to my website! 
    452453      def strip_tags(html)      
    453         return html if html.blank? 
    454         if html.index("<") 
    455           text = "" 
    456           tokenizer = HTML::Tokenizer.new(html) 
    457  
     454        return html if html.blank? || !html.index("<") 
     455        tokenizer = HTML::Tokenizer.new(html) 
     456 
     457        text = returning [] do |text| 
    458458          while token = tokenizer.next 
    459459            node = HTML::Node.parse(nil, 0, 0, token, false) 
     
    461461            text << node.to_s if node.class == HTML::Text   
    462462          end 
    463           # strip any comments, and if they have a newline at the end (ie. line with 
    464           # only a comment) strip that too 
    465           strip_tags(text.gsub(/<!--(.*?)-->[\n]?/m, "")) # Recurse - handle all dirty nested tags 
    466         else 
    467           html # already plain text 
    468         end  
     463        end 
     464         
     465        # strip any comments, and if they have a newline at the end (ie. line with 
     466        # only a comment) strip that too 
     467        # Recurse - handle all dirty nested tags 
     468        strip_tags(text.join.gsub(/<!--(.*?)-->[\n]?/m, "")) 
    469469      end 
    470470       
  • trunk/actionpack/lib/action_view/helpers/url_helper.rb

    r7548 r7592  
    473473          end 
    474474 
     475          if request_forgery_protection_token 
     476            submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); " 
     477            submit_function << "s.setAttribute('name', '_token'); s.setAttribute('value', '#{escape_javascript form_token}'); f.appendChild(s);" 
     478          end 
    475479          submit_function << "f.submit();" 
    476480        end 
  • trunk/actionpack/test/template/form_helper_test.rb

    r7541 r7592  
    712712      "/posts/#{post.id}" 
    713713    end 
     714     
     715    def request_forgery_protection_token 
     716      nil 
     717    end 
    714718end 
  • trunk/actionpack/test/template/form_tag_helper_test.rb

    r7423 r7592  
    178178    assert_dom_equal expected, _erbout 
    179179  end 
     180   
     181  def request_forgery_protection_token 
     182    nil 
     183     
     184  end 
    180185end 
  • trunk/actionpack/test/template/prototype_helper_test.rb

    r7468 r7592  
    6161 
    6262protected 
     63   
     64  def request_forgery_protection_token 
     65    nil 
     66  end 
     67   
    6368  def create_generator 
    6469    block = Proc.new { |*args| yield *args if block_given? }  
  • trunk/actionpack/test/template/scriptaculous_helper_test.rb

    r7396 r7592  
    9090      drop_receiving_element("droptarget1", :accept => ['tshirts','mugs'], :update => 'infobox') 
    9191  end 
     92   
     93  def request_forgery_protection_token 
     94    nil 
     95  end 
    9296end 
  • trunk/actionpack/test/template/url_helper_test.rb

    r7580 r7592  
    268268    assert_dom_equal "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%65%40%64%6f%6d%61%69%6e%2e%63%6f%6d%22%3e%4d%79%20%65%6d%61%69%6c%3c%2f%61%3e%27%29%3b'))</script>", mail_to("me@domain.com", "My email", :encode => "javascript", :replace_at => "(at)", :replace_dot => "(dot)") 
    269269  end 
     270   
     271  def request_forgery_protection_token 
     272    nil 
     273  end 
    270274end 
    271275