brakeman-min 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/FEATURES +16 -0
  2. data/README.md +118 -0
  3. data/WARNING_TYPES +69 -0
  4. data/bin/brakeman +269 -0
  5. data/lib/checks.rb +67 -0
  6. data/lib/checks/base_check.rb +353 -0
  7. data/lib/checks/check_cross_site_scripting.rb +324 -0
  8. data/lib/checks/check_default_routes.rb +29 -0
  9. data/lib/checks/check_evaluation.rb +27 -0
  10. data/lib/checks/check_execute.rb +110 -0
  11. data/lib/checks/check_file_access.rb +46 -0
  12. data/lib/checks/check_forgery_setting.rb +42 -0
  13. data/lib/checks/check_mail_to.rb +48 -0
  14. data/lib/checks/check_mass_assignment.rb +72 -0
  15. data/lib/checks/check_model_attributes.rb +36 -0
  16. data/lib/checks/check_nested_attributes.rb +34 -0
  17. data/lib/checks/check_redirect.rb +98 -0
  18. data/lib/checks/check_render.rb +65 -0
  19. data/lib/checks/check_send_file.rb +15 -0
  20. data/lib/checks/check_session_settings.rb +36 -0
  21. data/lib/checks/check_sql.rb +124 -0
  22. data/lib/checks/check_validation_regex.rb +60 -0
  23. data/lib/format/style.css +105 -0
  24. data/lib/processor.rb +83 -0
  25. data/lib/processors/alias_processor.rb +384 -0
  26. data/lib/processors/base_processor.rb +237 -0
  27. data/lib/processors/config_processor.rb +146 -0
  28. data/lib/processors/controller_alias_processor.rb +237 -0
  29. data/lib/processors/controller_processor.rb +202 -0
  30. data/lib/processors/erb_template_processor.rb +84 -0
  31. data/lib/processors/erubis_template_processor.rb +62 -0
  32. data/lib/processors/haml_template_processor.rb +131 -0
  33. data/lib/processors/lib/find_call.rb +176 -0
  34. data/lib/processors/lib/find_model_call.rb +39 -0
  35. data/lib/processors/lib/processor_helper.rb +36 -0
  36. data/lib/processors/lib/render_helper.rb +137 -0
  37. data/lib/processors/library_processor.rb +118 -0
  38. data/lib/processors/model_processor.rb +125 -0
  39. data/lib/processors/output_processor.rb +233 -0
  40. data/lib/processors/params_processor.rb +77 -0
  41. data/lib/processors/route_processor.rb +338 -0
  42. data/lib/processors/template_alias_processor.rb +86 -0
  43. data/lib/processors/template_processor.rb +55 -0
  44. data/lib/report.rb +651 -0
  45. data/lib/scanner.rb +215 -0
  46. data/lib/scanner_erubis.rb +43 -0
  47. data/lib/tracker.rb +144 -0
  48. data/lib/util.rb +141 -0
  49. data/lib/version.rb +1 -0
  50. data/lib/warning.rb +97 -0
  51. metadata +141 -0
@@ -0,0 +1,237 @@
1
+ require 'rubygems'
2
+ require 'sexp_processor'
3
+ require 'processors/lib/processor_helper'
4
+ require 'util'
5
+
6
+ #Base processor for most processors.
7
+ class BaseProcessor < SexpProcessor
8
+ include ProcessorHelper
9
+ include Util
10
+
11
+ attr_reader :ignore
12
+
13
+ #Return a new Processor.
14
+ def initialize tracker
15
+ super()
16
+ self.strict = false
17
+ self.auto_shift_type = false
18
+ self.require_empty = false
19
+ self.default_method = :process_default
20
+ self.warn_on_default = false
21
+ @last = nil
22
+ @tracker = tracker
23
+ @ignore = Sexp.new :ignore
24
+ @current_template = @current_module = @current_class = @current_method = nil
25
+ end
26
+
27
+ #Process a new scope. Removes expressions that are set to nil.
28
+ def process_scope exp
29
+ exp.shift
30
+ exp.map! do |e|
31
+ res = process e
32
+ if res.empty?
33
+ res = nil
34
+ else
35
+ res
36
+ end
37
+ end.compact
38
+ exp.unshift :scope
39
+ end
40
+
41
+ #Default processing.
42
+ def process_default exp
43
+ type = exp.shift
44
+ exp.each_with_index do |e, i|
45
+ if sexp? e and not e.empty?
46
+ exp[i] = process e
47
+ else
48
+ e
49
+ end
50
+ end
51
+ ensure
52
+ exp.unshift type
53
+ end
54
+
55
+ #Process an if statement.
56
+ def process_if exp
57
+ exp[1] = process exp[1]
58
+ exp[2] = process exp[2] if exp[2]
59
+ exp[3] = process exp[3] if exp[3]
60
+ exp
61
+ end
62
+
63
+ #Processes calls with blocks. Changes Sexp node type to :call_with_block
64
+ #
65
+ #s(:iter, CALL, {:lasgn|:masgn}, BLOCK)
66
+ def process_iter exp
67
+ call = process exp[1]
68
+ #deal with assignments somehow
69
+ if exp[3]
70
+ block = process exp[3]
71
+ block = nil if block.empty?
72
+ else
73
+ block = nil
74
+ end
75
+
76
+ call = Sexp.new(:call_with_block, call, exp[2], block).compact
77
+ call.line(exp.line)
78
+ call
79
+ end
80
+
81
+ #String with interpolation. Changes Sexp node type to :string_interp
82
+ def process_dstr exp
83
+ exp.shift
84
+ exp.map! do |e|
85
+ if e.is_a? String
86
+ e
87
+ elsif e[1].is_a? String
88
+ e[1]
89
+ else
90
+ res = process e
91
+ if res.empty?
92
+ nil
93
+ else
94
+ res
95
+ end
96
+ end
97
+ end.compact!
98
+
99
+ exp.unshift :string_interp
100
+ end
101
+
102
+ #Processes a block. Changes Sexp node type to :rlist
103
+ def process_block exp
104
+ exp.shift
105
+
106
+ exp.map! do |e|
107
+ process e
108
+ end
109
+
110
+ exp.unshift :rlist
111
+ end
112
+
113
+ #Processes the inside of an interpolated String.
114
+ #Changes Sexp node type to :string_eval
115
+ def process_evstr exp
116
+ exp[0] = :string_eval
117
+ exp[1] = process exp[1]
118
+ exp
119
+ end
120
+
121
+ #Processes an or keyword
122
+ def process_or exp
123
+ exp[1] = process exp[1]
124
+ exp[2] = process exp[2]
125
+ exp
126
+ end
127
+
128
+ #Processes an and keyword
129
+ def process_and exp
130
+ exp[1] = process exp[1]
131
+ exp[2] = process exp[2]
132
+ exp
133
+ end
134
+
135
+ #Processes a hash
136
+ def process_hash exp
137
+ exp.shift
138
+ exp.map! do |e|
139
+ if sexp? e
140
+ process e
141
+ else
142
+ e
143
+ end
144
+ end
145
+
146
+ exp.unshift :hash
147
+ end
148
+
149
+ #Processes the values in an argument list
150
+ def process_arglist exp
151
+ exp.shift
152
+ exp.map! do |e|
153
+ process e
154
+ end
155
+
156
+ exp.unshift :arglist
157
+ end
158
+
159
+ #Processes a local assignment
160
+ def process_lasgn exp
161
+ exp[2] = process exp[2]
162
+ exp
163
+ end
164
+
165
+ #Processes an instance variable assignment
166
+ def process_iasgn exp
167
+ exp[2] = process exp[2]
168
+ exp
169
+ end
170
+
171
+ #Processes an attribute assignment, which can be either x.y = 1 or x[:y] = 1
172
+ def process_attrasgn exp
173
+ exp[1] = process exp[1]
174
+ exp[3] = process exp[3]
175
+ exp
176
+ end
177
+
178
+ #Ignore ignore Sexps
179
+ def process_ignore exp
180
+ exp
181
+ end
182
+
183
+ #Generates :render node from call to render.
184
+ def make_render exp
185
+ render_type, value, rest = find_render_type exp[3]
186
+ rest = process rest
187
+ result = Sexp.new(:render, render_type, value, rest)
188
+ result.line(exp.line)
189
+ result
190
+ end
191
+
192
+ #Determines the type of a call to render.
193
+ #
194
+ #Possible types are:
195
+ #:action, :default :file, :inline, :js, :json, :nothing, :partial,
196
+ #:template, :text, :update, :xml
197
+ def find_render_type args
198
+ rest = Sexp.new(:hash)
199
+ type = nil
200
+ value = nil
201
+
202
+ if args.length == 2 and args[-1] == Sexp.new(:lit, :update)
203
+ return :update, nil, args[0..-2]
204
+ end
205
+
206
+ #Look for render :action, ... or render "action", ...
207
+ if string? args[1] or symbol? args[1]
208
+ type = :action
209
+ value = args[1]
210
+ elsif args[1].is_a? Symbol or args[1].is_a? String
211
+ type = :action
212
+ value = Sexp.new(:lit, args[1].to_sym)
213
+ elsif args[1].nil?
214
+ type = :default
215
+ elsif not hash? args[1]
216
+ type = :action
217
+ value = args[1]
218
+ end
219
+
220
+ if hash? args[-1]
221
+ hash_iterate(args[-1]) do |key, val|
222
+ case key[1]
223
+ when :action, :file, :inline, :js, :json, :nothing, :partial, :text, :update, :xml
224
+ type = key[1]
225
+ value = val
226
+ else
227
+ rest << key << val
228
+ end
229
+ end
230
+ end
231
+
232
+ type ||= :default
233
+ value ||= :default
234
+ args[-1] = rest
235
+ return type, value, rest
236
+ end
237
+ end
@@ -0,0 +1,146 @@
1
+ require 'processors/base_processor'
2
+ require 'processors/alias_processor'
3
+
4
+ #Replace block variable in
5
+ #
6
+ # Rails::Initializer.run |config|
7
+ #
8
+ #with this value so we can keep track of it.
9
+ RAILS_CONFIG = Sexp.new(:const, :"!BRAKEMAN_RAILS_CONFIG")
10
+
11
+ #Processes configuration. Results are put in tracker.config.
12
+ #
13
+ #Configuration of Rails via Rails::Initializer are stored in tracker.config[:rails].
14
+ #For example:
15
+ #
16
+ # Rails::Initializer.run |config|
17
+ # config.action_controller.session_store = :cookie_store
18
+ # end
19
+ #
20
+ #will be stored in
21
+ #
22
+ # tracker.config[:rails][:action_controller][:session_store]
23
+ #
24
+ #Values for tracker.config[:rails] will still be Sexps.
25
+ class ConfigProcessor < BaseProcessor
26
+ def initialize *args
27
+ super
28
+ @tracker.config[:rails] ||= {}
29
+ end
30
+
31
+ #Use this method to process configuration file
32
+ def process_config src
33
+ res = ConfigAliasProcessor.new.process_safely(src)
34
+ process res
35
+ end
36
+
37
+ #Check if config is set to use Erubis
38
+ def process_call exp
39
+ target = exp[1]
40
+ target = process target if sexp? target
41
+
42
+ if exp[2] == :gem and exp[3][1][1] == "erubis"
43
+ warn "[Notice] Using Erubis for ERB templates"
44
+ @tracker.config[:erubis] = true
45
+ end
46
+
47
+ exp
48
+ end
49
+
50
+ #Look for configuration settings
51
+ def process_attrasgn exp
52
+ if exp[1] == RAILS_CONFIG
53
+ #Get rid of '=' at end
54
+ attribute = exp[2].to_s[0..-2].to_sym
55
+ if exp[3].length > 2
56
+ #Multiple arguments?...not sure if this will ever happen
57
+ @tracker.config[:rails][exp[2]] = exp[3][1..-1]
58
+ else
59
+ @tracker.config[:rails][exp[2]] = exp[3][1]
60
+ end
61
+ elsif include_rails_config? exp
62
+ options = get_rails_config exp
63
+ level = @tracker.config[:rails]
64
+ options[0..-2].each do |o|
65
+ level[o] ||= {}
66
+ level = level[o]
67
+ end
68
+
69
+ level[options.last] = exp[3][1]
70
+ end
71
+
72
+ exp
73
+ end
74
+
75
+ #Check for Rails version
76
+ def process_cdecl exp
77
+ #Set Rails version required
78
+ if exp[1] == :RAILS_GEM_VERSION
79
+ @tracker.config[:rails_version] = exp[2][1]
80
+ end
81
+
82
+ exp
83
+ end
84
+
85
+ #Check if an expression includes a call to set Rails config
86
+ def include_rails_config? exp
87
+ target = exp[1]
88
+ if call? target
89
+ if target[1] == RAILS_CONFIG
90
+ true
91
+ else
92
+ include_rails_config? target
93
+ end
94
+ elsif target == RAILS_CONFIG
95
+ true
96
+ else
97
+ false
98
+ end
99
+ end
100
+
101
+ #Returns an array of symbols for each 'level' in the config
102
+ #
103
+ # config.action_controller.session_store = :cookie
104
+ #
105
+ #becomes
106
+ #
107
+ # [:action_controller, :session_store]
108
+ def get_rails_config exp
109
+ if sexp? exp and exp.node_type == :attrasgn
110
+ attribute = exp[2].to_s[0..-2].to_sym
111
+ get_rails_config(exp[1]) << attribute
112
+ elsif call? exp
113
+ if exp[1] == RAILS_CONFIG
114
+ [exp[2]]
115
+ else
116
+ get_rails_config(exp[1]) << exp[2]
117
+ end
118
+ else
119
+ raise "WHAT"
120
+ end
121
+ end
122
+ end
123
+
124
+ #This is necessary to replace block variable so we can track config settings
125
+ class ConfigAliasProcessor < AliasProcessor
126
+
127
+ RAILS_INIT = Sexp.new(:colon2, Sexp.new(:const, :Rails), :Initializer)
128
+
129
+ #Look for a call to
130
+ #
131
+ # Rails::Initializer.run do |config|
132
+ # ...
133
+ # end
134
+ #
135
+ #and replace config with RAILS_CONFIG
136
+ def process_iter exp
137
+ target = exp[1][1]
138
+ method = exp[1][2]
139
+
140
+ if sexp? target and target == RAILS_INIT and method == :run
141
+ exp[2][2] = RAILS_CONFIG
142
+ end
143
+
144
+ process_default exp
145
+ end
146
+ end
@@ -0,0 +1,237 @@
1
+ require 'processors/alias_processor'
2
+ require 'processors/lib/render_helper'
3
+
4
+ #Processes aliasing in controllers, but includes following
5
+ #renders in routes and putting variables into templates
6
+ class ControllerAliasProcessor < AliasProcessor
7
+ include RenderHelper
8
+
9
+ def initialize tracker
10
+ super()
11
+ @tracker = tracker
12
+ @rendered = false
13
+ @current_class = @current_module = @current_method = nil
14
+ end
15
+
16
+ #Processes a class which is probably a controller.
17
+ def process_class exp
18
+ @current_class = class_name(exp[1])
19
+ if @current_module
20
+ @current_class = (@current_module + "::" + @current_class.to_s).to_sym
21
+ end
22
+
23
+ process_default exp
24
+ end
25
+
26
+ #Processes a method definition, which may include
27
+ #processing any rendered templates.
28
+ def process_methdef exp
29
+ set_env_defaults
30
+ is_route = route? exp[1]
31
+ other_method = @current_method
32
+ @current_method = exp[1]
33
+ @rendered = false if is_route
34
+
35
+ env.scope do
36
+
37
+ if is_route
38
+ before_filter_list(@current_method, @current_class).each do |f|
39
+ process_before_filter f
40
+ end
41
+ end
42
+
43
+ process exp[3]
44
+
45
+ if is_route and not @rendered
46
+ process_default_render exp
47
+ end
48
+ end
49
+
50
+ @current_method = other_method
51
+ exp
52
+ end
53
+
54
+ #Look for calls to head()
55
+ def process_call exp
56
+ exp = super
57
+
58
+ if exp[2] == :head
59
+ @rendered = true
60
+ end
61
+ exp
62
+ end
63
+
64
+ #Check for +respond_to+
65
+ def process_call_with_block exp
66
+ process_default exp
67
+
68
+ if exp[1][2] == :respond_to
69
+ @rendered = true
70
+ end
71
+
72
+ exp
73
+ end
74
+
75
+ #Processes a call to a before filter.
76
+ #Basically, adds any instance variable assignments to the environment.
77
+ #TODO: method arguments?
78
+ def process_before_filter name
79
+ method = find_method name, @current_class
80
+
81
+ if method.nil?
82
+ warn "[Notice] Could not find filter #{name}" if OPTIONS[:debug]
83
+ return
84
+ end
85
+
86
+ processor = AliasProcessor.new
87
+ processor.process_safely(method[3])
88
+
89
+ processor.only_ivars.all.each do |variable, value|
90
+ env[variable] = value
91
+ end
92
+ end
93
+
94
+ #Processes the default template for the current action
95
+ def process_default_render exp
96
+ process_layout
97
+ process_template template_name, nil
98
+ end
99
+
100
+ #Process template and add the current class and method name as called_from info
101
+ def process_template name, args
102
+ super name, args, "#@current_class##@current_method"
103
+ end
104
+
105
+ #Turns a method name into a template name
106
+ def template_name name = nil
107
+ name ||= @current_method
108
+ name = name.to_s
109
+ if name.include? "/"
110
+ name
111
+ else
112
+ controller = @current_class.to_s.gsub("Controller", "")
113
+ controller.gsub!("::", "/")
114
+ underscore(controller + "/" + name.to_s)
115
+ end
116
+ end
117
+
118
+ #Determines default layout name
119
+ def layout_name
120
+ controller = @tracker.controllers[@current_class]
121
+
122
+ return controller[:layout] if controller[:layout]
123
+ return false if controller[:layout] == false
124
+
125
+ app_controller = @tracker.controllers[:ApplicationController]
126
+
127
+ return app_controller[:layout] if app_controller and app_controller[:layout]
128
+
129
+ nil
130
+ end
131
+
132
+ #Returns true if the given method name is also a route
133
+ def route? method
134
+ return true if @tracker.routes[:allow_all_actions]
135
+ routes = @tracker.routes[@current_class]
136
+ routes and (routes == :allow_all_actions or routes.include? method)
137
+ end
138
+
139
+ #Get list of filters, including those that are inherited
140
+ def before_filter_list method, klass
141
+ controller = @tracker.controllers[klass]
142
+ filters = []
143
+
144
+ while controller
145
+ filters = get_before_filters(method, controller) + filters
146
+
147
+ controller = @tracker.controllers[controller[:parent]]
148
+ end
149
+
150
+ filters
151
+ end
152
+
153
+ #Returns an array of filter names
154
+ def get_before_filters method, controller
155
+ filters = []
156
+ return filters unless controller[:options]
157
+ filter_list = controller[:options][:before_filters]
158
+ return filters unless filter_list
159
+
160
+ filter_list.each do |filter|
161
+ f = before_filter_to_hash filter
162
+ if f[:all] or
163
+ (f[:only] == method) or
164
+ (f[:only].is_a? Array and f[:only].include? method) or
165
+ (f[:except] == method) or
166
+ (f[:except].is_a? Array and not f[:except].include? method)
167
+
168
+ filters.concat f[:methods]
169
+ end
170
+ end
171
+
172
+ filters
173
+ end
174
+
175
+ #Returns a before filter as a hash table
176
+ def before_filter_to_hash args
177
+ filter = {}
178
+
179
+ #Process args for the uncommon but possible situation
180
+ #in which some variables are used in the filter.
181
+ args.each do |a|
182
+ if sexp? a
183
+ a = process_default a
184
+ end
185
+ end
186
+
187
+ filter[:methods] = [args[0][1]]
188
+
189
+ args[1..-1].each do |a|
190
+ filter[:methods] << a[1] unless a.node_type == :hash
191
+ end
192
+
193
+ if args[-1].node_type == :hash
194
+ option = args[-1][1][1]
195
+ value = args[-1][2]
196
+ case value.node_type
197
+ when :array
198
+ filter[option] = value[1..-1].map {|v| v[1] }
199
+ when :lit, :str
200
+ filter[option] = value[1]
201
+ else
202
+ warn "[Notice] Unknown before_filter value: #{option} => #{value}" if OPTIONS[:debug]
203
+ end
204
+ else
205
+ filter[:all] = true
206
+ end
207
+
208
+ filter
209
+ end
210
+
211
+ #Finds a method in the given class or a parent class
212
+ def find_method method_name, klass
213
+ return nil if sexp? method_name
214
+ method_name = method_name.to_sym
215
+ controller = @tracker.controllers[klass]
216
+ controller ||= @tracker.libs[klass]
217
+
218
+ if klass and controller
219
+ method = controller[:public][method_name]
220
+ method ||= controller[:private][method_name]
221
+ method ||= controller[:protected][method_name]
222
+
223
+ if method.nil?
224
+ controller[:includes].each do |included|
225
+ method = find_method method_name, included
226
+ return method if method
227
+ end
228
+
229
+ find_method method_name, controller[:parent]
230
+ else
231
+ method
232
+ end
233
+ else
234
+ nil
235
+ end
236
+ end
237
+ end