railroader 4.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +1091 -0
  3. data/FEATURES +16 -0
  4. data/README.md +174 -0
  5. data/bin/railroader +8 -0
  6. data/lib/railroader/app_tree.rb +191 -0
  7. data/lib/railroader/call_index.rb +219 -0
  8. data/lib/railroader/checks/base_check.rb +505 -0
  9. data/lib/railroader/checks/check_basic_auth.rb +88 -0
  10. data/lib/railroader/checks/check_basic_auth_timing_attack.rb +33 -0
  11. data/lib/railroader/checks/check_content_tag.rb +200 -0
  12. data/lib/railroader/checks/check_create_with.rb +74 -0
  13. data/lib/railroader/checks/check_cross_site_scripting.rb +381 -0
  14. data/lib/railroader/checks/check_default_routes.rb +86 -0
  15. data/lib/railroader/checks/check_deserialize.rb +56 -0
  16. data/lib/railroader/checks/check_detailed_exceptions.rb +55 -0
  17. data/lib/railroader/checks/check_digest_dos.rb +38 -0
  18. data/lib/railroader/checks/check_divide_by_zero.rb +42 -0
  19. data/lib/railroader/checks/check_dynamic_finders.rb +48 -0
  20. data/lib/railroader/checks/check_escape_function.rb +21 -0
  21. data/lib/railroader/checks/check_evaluation.rb +35 -0
  22. data/lib/railroader/checks/check_execute.rb +189 -0
  23. data/lib/railroader/checks/check_file_access.rb +71 -0
  24. data/lib/railroader/checks/check_file_disclosure.rb +35 -0
  25. data/lib/railroader/checks/check_filter_skipping.rb +31 -0
  26. data/lib/railroader/checks/check_forgery_setting.rb +81 -0
  27. data/lib/railroader/checks/check_header_dos.rb +31 -0
  28. data/lib/railroader/checks/check_i18n_xss.rb +48 -0
  29. data/lib/railroader/checks/check_jruby_xml.rb +36 -0
  30. data/lib/railroader/checks/check_json_encoding.rb +47 -0
  31. data/lib/railroader/checks/check_json_parsing.rb +107 -0
  32. data/lib/railroader/checks/check_link_to.rb +132 -0
  33. data/lib/railroader/checks/check_link_to_href.rb +146 -0
  34. data/lib/railroader/checks/check_mail_to.rb +49 -0
  35. data/lib/railroader/checks/check_mass_assignment.rb +196 -0
  36. data/lib/railroader/checks/check_mime_type_dos.rb +39 -0
  37. data/lib/railroader/checks/check_model_attr_accessible.rb +55 -0
  38. data/lib/railroader/checks/check_model_attributes.rb +119 -0
  39. data/lib/railroader/checks/check_model_serialize.rb +67 -0
  40. data/lib/railroader/checks/check_nested_attributes.rb +38 -0
  41. data/lib/railroader/checks/check_nested_attributes_bypass.rb +58 -0
  42. data/lib/railroader/checks/check_number_to_currency.rb +74 -0
  43. data/lib/railroader/checks/check_permit_attributes.rb +43 -0
  44. data/lib/railroader/checks/check_quote_table_name.rb +40 -0
  45. data/lib/railroader/checks/check_redirect.rb +256 -0
  46. data/lib/railroader/checks/check_regex_dos.rb +68 -0
  47. data/lib/railroader/checks/check_render.rb +97 -0
  48. data/lib/railroader/checks/check_render_dos.rb +37 -0
  49. data/lib/railroader/checks/check_render_inline.rb +53 -0
  50. data/lib/railroader/checks/check_response_splitting.rb +21 -0
  51. data/lib/railroader/checks/check_route_dos.rb +42 -0
  52. data/lib/railroader/checks/check_safe_buffer_manipulation.rb +31 -0
  53. data/lib/railroader/checks/check_sanitize_methods.rb +112 -0
  54. data/lib/railroader/checks/check_secrets.rb +40 -0
  55. data/lib/railroader/checks/check_select_tag.rb +59 -0
  56. data/lib/railroader/checks/check_select_vulnerability.rb +60 -0
  57. data/lib/railroader/checks/check_send.rb +47 -0
  58. data/lib/railroader/checks/check_send_file.rb +19 -0
  59. data/lib/railroader/checks/check_session_manipulation.rb +35 -0
  60. data/lib/railroader/checks/check_session_settings.rb +176 -0
  61. data/lib/railroader/checks/check_simple_format.rb +58 -0
  62. data/lib/railroader/checks/check_single_quotes.rb +101 -0
  63. data/lib/railroader/checks/check_skip_before_filter.rb +60 -0
  64. data/lib/railroader/checks/check_sql.rb +700 -0
  65. data/lib/railroader/checks/check_sql_cves.rb +106 -0
  66. data/lib/railroader/checks/check_ssl_verify.rb +48 -0
  67. data/lib/railroader/checks/check_strip_tags.rb +89 -0
  68. data/lib/railroader/checks/check_symbol_dos.rb +71 -0
  69. data/lib/railroader/checks/check_symbol_dos_cve.rb +30 -0
  70. data/lib/railroader/checks/check_translate_bug.rb +45 -0
  71. data/lib/railroader/checks/check_unsafe_reflection.rb +50 -0
  72. data/lib/railroader/checks/check_unscoped_find.rb +57 -0
  73. data/lib/railroader/checks/check_validation_regex.rb +116 -0
  74. data/lib/railroader/checks/check_weak_hash.rb +148 -0
  75. data/lib/railroader/checks/check_without_protection.rb +80 -0
  76. data/lib/railroader/checks/check_xml_dos.rb +45 -0
  77. data/lib/railroader/checks/check_yaml_parsing.rb +121 -0
  78. data/lib/railroader/checks.rb +209 -0
  79. data/lib/railroader/codeclimate/engine_configuration.rb +97 -0
  80. data/lib/railroader/commandline.rb +179 -0
  81. data/lib/railroader/differ.rb +66 -0
  82. data/lib/railroader/file_parser.rb +54 -0
  83. data/lib/railroader/format/style.css +133 -0
  84. data/lib/railroader/options.rb +339 -0
  85. data/lib/railroader/parsers/rails2_erubis.rb +6 -0
  86. data/lib/railroader/parsers/rails2_xss_plugin_erubis.rb +48 -0
  87. data/lib/railroader/parsers/rails3_erubis.rb +81 -0
  88. data/lib/railroader/parsers/template_parser.rb +108 -0
  89. data/lib/railroader/processor.rb +102 -0
  90. data/lib/railroader/processors/alias_processor.rb +1229 -0
  91. data/lib/railroader/processors/base_processor.rb +295 -0
  92. data/lib/railroader/processors/config_processor.rb +14 -0
  93. data/lib/railroader/processors/controller_alias_processor.rb +278 -0
  94. data/lib/railroader/processors/controller_processor.rb +249 -0
  95. data/lib/railroader/processors/erb_template_processor.rb +77 -0
  96. data/lib/railroader/processors/erubis_template_processor.rb +92 -0
  97. data/lib/railroader/processors/gem_processor.rb +64 -0
  98. data/lib/railroader/processors/haml_template_processor.rb +191 -0
  99. data/lib/railroader/processors/lib/basic_processor.rb +37 -0
  100. data/lib/railroader/processors/lib/call_conversion_helper.rb +90 -0
  101. data/lib/railroader/processors/lib/find_all_calls.rb +224 -0
  102. data/lib/railroader/processors/lib/find_call.rb +183 -0
  103. data/lib/railroader/processors/lib/find_return_value.rb +166 -0
  104. data/lib/railroader/processors/lib/module_helper.rb +111 -0
  105. data/lib/railroader/processors/lib/processor_helper.rb +88 -0
  106. data/lib/railroader/processors/lib/rails2_config_processor.rb +145 -0
  107. data/lib/railroader/processors/lib/rails2_route_processor.rb +313 -0
  108. data/lib/railroader/processors/lib/rails3_config_processor.rb +132 -0
  109. data/lib/railroader/processors/lib/rails3_route_processor.rb +308 -0
  110. data/lib/railroader/processors/lib/render_helper.rb +181 -0
  111. data/lib/railroader/processors/lib/render_path.rb +107 -0
  112. data/lib/railroader/processors/lib/route_helper.rb +68 -0
  113. data/lib/railroader/processors/lib/safe_call_helper.rb +16 -0
  114. data/lib/railroader/processors/library_processor.rb +74 -0
  115. data/lib/railroader/processors/model_processor.rb +91 -0
  116. data/lib/railroader/processors/output_processor.rb +144 -0
  117. data/lib/railroader/processors/route_processor.rb +17 -0
  118. data/lib/railroader/processors/slim_template_processor.rb +111 -0
  119. data/lib/railroader/processors/template_alias_processor.rb +118 -0
  120. data/lib/railroader/processors/template_processor.rb +85 -0
  121. data/lib/railroader/report/config/remediation.yml +71 -0
  122. data/lib/railroader/report/ignore/config.rb +153 -0
  123. data/lib/railroader/report/ignore/interactive.rb +362 -0
  124. data/lib/railroader/report/pager.rb +112 -0
  125. data/lib/railroader/report/renderer.rb +24 -0
  126. data/lib/railroader/report/report_base.rb +292 -0
  127. data/lib/railroader/report/report_codeclimate.rb +79 -0
  128. data/lib/railroader/report/report_csv.rb +55 -0
  129. data/lib/railroader/report/report_hash.rb +23 -0
  130. data/lib/railroader/report/report_html.rb +216 -0
  131. data/lib/railroader/report/report_json.rb +45 -0
  132. data/lib/railroader/report/report_markdown.rb +107 -0
  133. data/lib/railroader/report/report_table.rb +117 -0
  134. data/lib/railroader/report/report_tabs.rb +17 -0
  135. data/lib/railroader/report/report_text.rb +198 -0
  136. data/lib/railroader/report/templates/controller_overview.html.erb +22 -0
  137. data/lib/railroader/report/templates/controller_warnings.html.erb +21 -0
  138. data/lib/railroader/report/templates/error_overview.html.erb +29 -0
  139. data/lib/railroader/report/templates/header.html.erb +58 -0
  140. data/lib/railroader/report/templates/ignored_warnings.html.erb +25 -0
  141. data/lib/railroader/report/templates/model_warnings.html.erb +21 -0
  142. data/lib/railroader/report/templates/overview.html.erb +38 -0
  143. data/lib/railroader/report/templates/security_warnings.html.erb +23 -0
  144. data/lib/railroader/report/templates/template_overview.html.erb +21 -0
  145. data/lib/railroader/report/templates/view_warnings.html.erb +34 -0
  146. data/lib/railroader/report/templates/warning_overview.html.erb +17 -0
  147. data/lib/railroader/report.rb +88 -0
  148. data/lib/railroader/rescanner.rb +483 -0
  149. data/lib/railroader/scanner.rb +321 -0
  150. data/lib/railroader/tracker/collection.rb +93 -0
  151. data/lib/railroader/tracker/config.rb +154 -0
  152. data/lib/railroader/tracker/constants.rb +171 -0
  153. data/lib/railroader/tracker/controller.rb +161 -0
  154. data/lib/railroader/tracker/library.rb +17 -0
  155. data/lib/railroader/tracker/model.rb +90 -0
  156. data/lib/railroader/tracker/template.rb +33 -0
  157. data/lib/railroader/tracker.rb +362 -0
  158. data/lib/railroader/util.rb +503 -0
  159. data/lib/railroader/version.rb +3 -0
  160. data/lib/railroader/warning.rb +294 -0
  161. data/lib/railroader/warning_codes.rb +117 -0
  162. data/lib/railroader.rb +544 -0
  163. data/lib/ruby_parser/bm_sexp.rb +626 -0
  164. data/lib/ruby_parser/bm_sexp_processor.rb +116 -0
  165. metadata +386 -0
@@ -0,0 +1,171 @@
1
+ require 'railroader/processors/output_processor'
2
+
3
+ module Railroader
4
+ class Constant
5
+ attr_reader :name, :name_array, :file, :value, :context
6
+
7
+ def initialize name, value, context = {}
8
+ set_name name, context
9
+ @value = value
10
+ @context = context
11
+
12
+ if @context
13
+ if @context[:class].is_a? Railroader::Controller
14
+ @context[:class] = @context[:class].name
15
+ end
16
+
17
+ @file = @context[:file]
18
+ end
19
+ end
20
+
21
+ def line
22
+ if @value.is_a? Sexp
23
+ @value.line
24
+ end
25
+ end
26
+
27
+ def set_name name, context
28
+ @name = name
29
+ @name_array = Constants.constant_as_array(name)
30
+ end
31
+
32
+ def match? name
33
+ if name == @name
34
+ return true
35
+ elsif name.is_a? Sexp and name.node_type == :const and name.value == @name
36
+ return true
37
+ elsif name.is_a? Symbol and name.value == @name
38
+ return true
39
+ elsif name.class == Array
40
+ name == @name_array or
41
+ @name_array.reverse.zip(name.reverse).reduce(true) { |m, a| a[1] ? a[0] == a[1] && m : m }
42
+ else
43
+ false
44
+ end
45
+ end
46
+ end
47
+
48
+ class Constants
49
+ include Railroader::Util
50
+
51
+ def initialize
52
+ @constants = Hash.new { |h, k| h[k] = [] }
53
+ end
54
+
55
+ def size
56
+ @constants.length
57
+ end
58
+
59
+ def [] exp
60
+ return unless constant? exp
61
+ match = find_constant exp
62
+
63
+ if match
64
+ match.value
65
+ else
66
+ nil
67
+ end
68
+ end
69
+
70
+ def find_constant exp
71
+ base_name = Constants.get_constant_base_name(exp)
72
+
73
+ if @constants.key? base_name
74
+ @constants[base_name].find do |c|
75
+ if c.match? exp
76
+ return c
77
+ end
78
+ end
79
+
80
+ name_array = Constants.constant_as_array(exp)
81
+
82
+ # Avoid losing info about dynamic constant values
83
+ return unless name_array.all? { |n| constant? n or n.is_a? Symbol }
84
+
85
+ @constants[base_name].find do |c|
86
+ if c.match? name_array
87
+ return c
88
+ end
89
+ end
90
+ end
91
+
92
+ nil
93
+ end
94
+
95
+ def find_all exp
96
+ base_name = Constants.get_constant_base_name(exp)
97
+ @constants[base_name]
98
+ end
99
+
100
+ def add name, value, context = nil
101
+ if call? value and value.method == :freeze
102
+ value = value.target
103
+ end
104
+
105
+ base_name = Constants.get_constant_base_name(name)
106
+ @constants[base_name] << Constant.new(name, value, context)
107
+ end
108
+
109
+ LITERALS = [:lit, :false, :str, :true, :array, :hash]
110
+ def literal? exp
111
+ exp.is_a? Sexp and LITERALS.include? exp.node_type
112
+ end
113
+
114
+ def get_literal name
115
+ if x = self[name] and literal? x
116
+ x
117
+ else
118
+ nil
119
+ end
120
+ end
121
+
122
+ def each
123
+ @constants.each do |name, values|
124
+ values.each do |constant|
125
+ yield constant
126
+ end
127
+ end
128
+ end
129
+
130
+ def self.constant_as_array exp
131
+ res = []
132
+ while exp
133
+ if exp.is_a? Sexp
134
+ case exp.node_type
135
+ when :const
136
+ res << exp.value
137
+ exp = nil
138
+ when :colon3
139
+ res << exp.value << :""
140
+ exp = nil
141
+ when :colon2
142
+ res << exp.last
143
+ exp = exp[1]
144
+ else
145
+ res << exp
146
+ exp = nil
147
+ end
148
+ else
149
+ res << exp
150
+ exp = nil
151
+ end
152
+ end
153
+
154
+ res.reverse!
155
+ res
156
+ end
157
+
158
+ def self.get_constant_base_name exp
159
+ return exp unless exp.is_a? Sexp
160
+
161
+ case exp.node_type
162
+ when :const, :colon3
163
+ exp.value
164
+ when :colon2
165
+ exp.last
166
+ else
167
+ exp
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,161 @@
1
+ require 'railroader/tracker/collection'
2
+
3
+ module Railroader
4
+ module ControllerMethods
5
+ attr_accessor :layout
6
+
7
+ def initialize_controller
8
+ @options[:before_filters] = []
9
+ @options[:skip_filters] = []
10
+ @layout = nil
11
+ @skip_filter_cache = nil
12
+ @before_filter_cache = nil
13
+ end
14
+
15
+ def protect_from_forgery?
16
+ @options[:protect_from_forgery]
17
+ end
18
+
19
+ def add_before_filter exp
20
+ @options[:before_filters] << exp
21
+ end
22
+
23
+ def prepend_before_filter exp
24
+ @options[:before_filters].unshift exp
25
+ end
26
+
27
+ def before_filters
28
+ @options[:before_filters]
29
+ end
30
+
31
+ def skip_filter exp
32
+ @options[:skip_filters] << exp
33
+ end
34
+
35
+ def skip_filters
36
+ @options[:skip_filters]
37
+ end
38
+
39
+ def before_filter_list processor, method
40
+ controller = self
41
+ filters = []
42
+
43
+ while controller
44
+ filters = controller.get_before_filters(processor, method) + filters
45
+
46
+ controller = tracker.controllers[controller.parent] ||
47
+ tracker.libs[controller.parent]
48
+ end
49
+
50
+ remove_skipped_filters processor, filters, method
51
+ end
52
+
53
+ def get_skipped_filters processor, method
54
+ filters = []
55
+
56
+ if @skip_filter_cache.nil?
57
+ @skip_filter_cache = skip_filters.map do |filter|
58
+ before_filter_to_hash(processor, filter.args)
59
+ end
60
+ end
61
+
62
+ @skip_filter_cache.each do |f|
63
+ if filter_includes_method? f, method
64
+ filters.concat f[:methods]
65
+ else
66
+ end
67
+ end
68
+
69
+ filters
70
+ end
71
+
72
+
73
+ def remove_skipped_filters processor, filters, method
74
+ controller = self
75
+
76
+ while controller
77
+ filters = filters - controller.get_skipped_filters(processor, method)
78
+
79
+ controller = tracker.controllers[controller.parent] ||
80
+ tracker.libs[controller.parent]
81
+ end
82
+
83
+ filters
84
+ end
85
+
86
+ def get_before_filters processor, method
87
+ filters = []
88
+
89
+ if @before_filter_cache.nil?
90
+ @before_filter_cache = []
91
+
92
+ before_filters.each do |filter|
93
+ @before_filter_cache << before_filter_to_hash(processor, filter.args)
94
+ end
95
+ end
96
+
97
+ @before_filter_cache.each do |f|
98
+ if filter_includes_method? f, method
99
+ filters.concat f[:methods]
100
+ end
101
+ end
102
+
103
+ filters
104
+ end
105
+
106
+ def before_filter_to_hash processor, args
107
+ filter = {}
108
+
109
+ #Process args for the uncommon but possible situation
110
+ #in which some variables are used in the filter.
111
+ args.each do |a|
112
+ if sexp? a
113
+ a = processor.process_default a
114
+ end
115
+ end
116
+
117
+ filter[:methods] = []
118
+
119
+ args.each do |a|
120
+ filter[:methods] << a[1] if a.node_type == :lit
121
+ end
122
+
123
+ if args[-1].node_type == :hash
124
+ option = args[-1][1][1]
125
+ value = args[-1][2]
126
+ case value.node_type
127
+ when :array
128
+ filter[option] = value[1..-1].map {|v| v[1] }
129
+ when :lit, :str
130
+ filter[option] = value[1]
131
+ else
132
+ Railroader.debug "[Notice] Unknown before_filter value: #{option} => #{value}"
133
+ end
134
+ else
135
+ filter[:all] = true
136
+ end
137
+
138
+ filter
139
+ end
140
+
141
+ private
142
+
143
+ def filter_includes_method? filter_rule, method_name
144
+ filter_rule[:all] or
145
+ (filter_rule[:only] == method_name) or
146
+ (filter_rule[:only].is_a? Array and filter_rule[:only].include? method_name) or
147
+ (filter_rule[:except].is_a? Symbol and filter_rule[:except] != method_name) or
148
+ (filter_rule[:except].is_a? Array and not filter_rule[:except].include? method_name)
149
+ end
150
+ end
151
+
152
+ class Controller < Railroader::Collection
153
+ include ControllerMethods
154
+
155
+ def initialize name, parent, file_name, src, tracker
156
+ super
157
+ initialize_controller
158
+ @collection = tracker.controllers
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,17 @@
1
+ require 'railroader/tracker/collection'
2
+ require 'railroader/tracker/controller'
3
+ require 'railroader/tracker/model'
4
+
5
+ module Railroader
6
+ class Library < Railroader::Collection
7
+ include ControllerMethods
8
+ include ModelMethods
9
+
10
+ def initialize name, parent, file_name, src, tracker
11
+ super
12
+ initialize_controller
13
+ initialize_model
14
+ @collection = tracker.libs
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ require 'railroader/tracker/collection'
2
+
3
+ module Railroader
4
+ module ModelMethods
5
+ attr_reader :associations, :attr_accessible, :role_accessible
6
+
7
+ def initialize_model
8
+ @associations = {}
9
+ @role_accessible = []
10
+ @attr_accessible = nil
11
+ end
12
+
13
+ def association? method_name
14
+ @associations.each do |name, args|
15
+ args.each do |arg|
16
+ if symbol? arg and arg.value == method_name
17
+ return true
18
+ end
19
+ end
20
+ end
21
+
22
+ false
23
+ end
24
+
25
+ def unprotected_model?
26
+ @attr_accessible.nil? and !parent_classes_protected? and ancestor?(:"ActiveRecord::Base")
27
+ end
28
+
29
+ # go up the chain of parent classes to see if any have attr_accessible
30
+ def parent_classes_protected? seen={}
31
+ seen[self.name] = true
32
+
33
+ if @attr_accessible or self.includes.include? :"ActiveModel::ForbiddenAttributesProtection"
34
+ true
35
+ elsif parent = tracker.models[self.parent] and !seen[self.parent]
36
+ parent.parent_classes_protected? seen
37
+ else
38
+ false
39
+ end
40
+ end
41
+
42
+ def set_attr_accessible exp = nil
43
+ if exp
44
+ args = []
45
+
46
+ exp.each_arg do |e|
47
+ if node_type? e, :lit
48
+ args << e.value
49
+ elsif hash? e
50
+ @role_accessible.concat args
51
+ end
52
+ end
53
+
54
+ @attr_accessible ||= []
55
+ @attr_accessible.concat args
56
+ else
57
+ @attr_accessible ||= []
58
+ end
59
+ end
60
+
61
+ def set_attr_protected exp
62
+ add_option :attr_protected, exp
63
+ end
64
+
65
+ def attr_protected
66
+ @options[:attr_protected]
67
+ end
68
+ end
69
+
70
+ class Model < Railroader::Collection
71
+ include ModelMethods
72
+
73
+ ASSOCIATIONS = Set[:belongs_to, :has_one, :has_many, :has_and_belongs_to_many]
74
+
75
+ def initialize name, parent, file_name, src, tracker
76
+ super
77
+ initialize_model
78
+ @collection = tracker.models
79
+ end
80
+
81
+ def add_option name, exp
82
+ if ASSOCIATIONS.include? name
83
+ @associations[name] ||= []
84
+ @associations[name].concat exp.args
85
+ else
86
+ super name, exp.arglist.line(exp.line)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,33 @@
1
+ require 'railroader/tracker/collection'
2
+
3
+ module Railroader
4
+ class Template < Railroader::Collection
5
+ attr_accessor :type
6
+ attr_reader :render_path
7
+ attr_writer :src
8
+
9
+ def initialize name, called_from, file_name, tracker
10
+ super name, nil, file_name, nil, tracker
11
+ @render_path = called_from
12
+ @outputs = []
13
+ end
14
+
15
+ def add_output exp
16
+ @outputs << exp
17
+ end
18
+
19
+ def each_output
20
+ @outputs.each do |o|
21
+ yield o
22
+ end
23
+ end
24
+
25
+ def rendered_from_controller?
26
+ if @render_path
27
+ @render_path.rendered_from_controller?
28
+ else
29
+ false
30
+ end
31
+ end
32
+ end
33
+ end