lib/brakeman/checks/check_sql.rb in brakeman-min-3.4.1 vs lib/brakeman/checks/check_sql.rb in brakeman-min-3.5.0
- old
+ new
@@ -12,37 +12,48 @@
Brakeman::Checks.add self
@description = "Check for SQL injection"
def run_check
- @sql_targets = [:all, :average, :calculate, :count, :count_by_sql, :exists?, :delete_all, :destroy_all,
- :find, :find_by_sql, :first, :last, :maximum, :minimum, :pluck, :sum, :update_all]
- @sql_targets.concat [:from, :group, :having, :joins, :lock, :order, :reorder, :select, :where] if tracker.options[:rails3]
+ narrow_targets = [:exists?, :select]
+
+ @sql_targets = [:average, :calculate, :count, :count_by_sql, :delete_all, :destroy_all,
+ :find_by_sql, :maximum, :minimum, :pluck, :sum, :update_all]
+ @sql_targets.concat [:from, :group, :having, :joins, :lock, :order, :reorder, :where] if tracker.options[:rails3]
@sql_targets << :find_by << :find_by! if tracker.options[:rails4]
+ if version_between?("2.0.0", "3.9.9") or tracker.config.rails_version.nil?
+ @sql_targets << :first << :last << :all
+ end
+
+ if version_between?("2.0.0", "4.0.99") or tracker.config.rails_version.nil?
+ @sql_targets << :find
+ end
+
@connection_calls = [:delete, :execute, :insert, :select_all, :select_one,
:select_rows, :select_value, :select_values]
if tracker.options[:rails3]
@connection_calls.concat [:exec_delete, :exec_insert, :exec_query, :exec_update]
else
@connection_calls.concat [:add_limit!, :add_offset_limit!, :add_lock!]
end
+ @expected_targets = active_record_models.keys + [:connection, :"ActiveRecord::Base"]
+
Brakeman.debug "Finding possible SQL calls on models"
- calls = tracker.find_call :targets => active_record_models.keys,
- :methods => @sql_targets,
- :chained => true
+ calls = tracker.find_call(:methods => @sql_targets, :nested => true)
+ calls.concat tracker.find_call(:targets => active_record_models.keys, :methods => narrow_targets, :chained => true)
+
Brakeman.debug "Finding possible SQL calls with no target"
calls.concat tracker.find_call(:target => nil, :methods => @sql_targets)
Brakeman.debug "Finding possible SQL calls using constantized()"
calls.concat tracker.find_call(:methods => @sql_targets).select { |result| constantize_call? result }
- connect_targets = active_record_models.keys + [:connection, :"ActiveRecord::Base"]
- calls.concat tracker.find_call(:targets => connect_targets, :methods => @connection_calls, :chained => true).select { |result| connect_call? result }
+ calls.concat tracker.find_call(:targets => @expected_targets, :methods => @connection_calls, :chained => true).select { |result| connect_call? result }
Brakeman.debug "Finding calls to named_scope or scope"
calls.concat find_scope_calls
Brakeman.debug "Processing possible SQL calls"
@@ -201,10 +212,21 @@
else
confidence = CONFIDENCE[:med]
user_input = dangerous_value
end
+ if result[:call].target and result[:chain] and not @expected_targets.include? result[:chain].first
+ confidence = case confidence
+ when CONFIDENCE[:high]
+ CONFIDENCE[:med]
+ when CONFIDENCE[:med]
+ CONFIDENCE[:low]
+ else
+ confidence
+ end
+ end
+
warn :result => result,
:warning_type => "SQL Injection",
:warning_code => :sql_injection,
:message => "Possible SQL injection",
:user_input => user_input,
@@ -427,11 +449,11 @@
check_hash_values exp unless ignore_hash
when :if
unsafe_sql? exp.then_clause or unsafe_sql? exp.else_clause
when :call
unless IGNORE_METHODS_IN_SQL.include? exp.method
- if has_immediate_user_input? exp or has_immediate_model? exp
+ if has_immediate_user_input? exp
exp
elsif exp.method == :to_s
find_dangerous_value exp.target, ignore_hash
else
check_call exp
@@ -444,10 +466,10 @@
nil
end
when :block, :rlist
unsafe_sql? exp.last
else
- if has_immediate_user_input? exp or has_immediate_model? exp
+ if has_immediate_user_input? exp
exp
else
nil
end
end