Reports any calls to redirect_to which include parameters in the arguments.
For example:
redirect_to params.merge(:action => :elsewhere)
Check if method is actually an association in a Model
# File lib/brakeman/checks/check_redirect.rb, line 155 def association? model_name, meth if call? model_name return association? model_name.target, meth elsif model_name? model_name model = tracker.models[class_name(model_name)] else return false end return false unless model model[:associations].each do |name, args| args.each do |arg| if symbol? arg and arg.value == meth return true end end end false end
url_for is only_path => true by default. This checks to see if it is set to false for some reason.
# File lib/brakeman/checks/check_redirect.rb, line 113 def check_url_for call arg = call.first_arg if hash? arg if value = hash_access(arg, :only_path) return false if false?(value) end end true end
Returns true if exp is (probably) a decorated model instance using the Draper gem
# File lib/brakeman/checks/check_redirect.rb, line 141 def decorated_model? exp if node_type? exp, :or decorated_model? exp.lhs or decorated_model? exp.rhs else tracker.config[:gems] and tracker.config[:gems][:draper] and call? exp and node_type?(exp.target, :const) and exp.target.value.to_s.match(/Decorator$/) and exp.method == :decorate end end
Custom check for user input. First looks to see if the user input is being output directly. This is necessary because of tracker.options which can be used to enable/disable reporting output of method calls which use user input as arguments.
# File lib/brakeman/checks/check_redirect.rb, line 56 def include_user_input? call, immediate = :immediate Brakeman.debug "Checking if call includes user input" arg = call.first_arg # if the first argument is an array, rails assumes you are building a # polymorphic route, which will never jump off-host return false if array? arg if tracker.options[:ignore_redirect_to_model] if model_instance?(arg) or decorated_model?(arg) return false end end if res = has_immediate_model?(arg) return Match.new(immediate, res) elsif call? arg if request_value? arg return Match.new(immediate, arg) elsif request_value? arg.target return Match.new(immediate, arg.target) elsif arg.method == :url_for and include_user_input? arg return Match.new(immediate, arg) #Ignore helpers like some_model_url? elsif arg.method.to_s =~ /_(url|path)\z/ return false end elsif request_value? arg return Match.new(immediate, arg) end if tracker.options[:check_arguments] and call? arg include_user_input? arg, false #I'm doubting if this is really necessary... else false end end
Returns true if exp is (probably) a model instance
# File lib/brakeman/checks/check_redirect.rb, line 126 def model_instance? exp if node_type? exp, :or model_instance? exp.lhs or model_instance? exp.rhs elsif call? exp if model_name? exp.target and (@model_find_calls.include? exp.method or exp.method.to_s.match(/^find_by_/)) true else association?(exp.target, exp.method) end end end
Checks redirect_to arguments for +only_path => true+ which essentially nullifies the danger posed by redirecting with user input
# File lib/brakeman/checks/check_redirect.rb, line 97 def only_path? call arg = call.first_arg if hash? arg if value = hash_access(arg, :only_path) return true if true?(value) end elsif call? arg and arg.method == :url_for return check_url_for(arg) end false end
# File lib/brakeman/checks/check_redirect.rb, line 27 def process_result result return if duplicate? result call = result[:call] method = call.method if method == :redirect_to and not only_path?(call) and res = include_user_input?(call) add_result result if res.type == :immediate confidence = CONFIDENCE[:high] else confidence = CONFIDENCE[:low] end warn :result => result, :warning_type => "Redirect", :message => "Possible unprotected redirect", :code => call, :user_input => res.match, :confidence => confidence end end
# File lib/brakeman/checks/check_redirect.rb, line 13 def run_check Brakeman.debug "Finding calls to redirect_to()" @model_find_calls = Set[:all, :find, :find_by_sql, :first, :last, :new] if tracker.options[:rails3] @model_find_calls.merge [:from, :group, :having, :joins, :lock, :order, :reorder, :select, :where] end @tracker.find_call(:target => false, :method => :redirect_to).each do |res| process_result res end end
Generated with the Darkfish Rdoc Generator 2.