brakeman 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -38,6 +38,10 @@ OptionParser.new do |opts|
38
38
  options[:ignore_model_output] = true
39
39
  end
40
40
 
41
+ opts.on "-e", "--escape-html", "Escape HTML by default" do
42
+ options[:escape_html] = true
43
+ end
44
+
41
45
  opts.on "-r", "--report-direct", "Only report direct use of untrusted data" do |option|
42
46
  options[:check_arguments] = !option
43
47
  end
@@ -30,6 +30,8 @@ class CheckCrossSiteScripting < BaseCheck
30
30
 
31
31
  HAML_HELPERS = Sexp.new(:colon2, Sexp.new(:const, :Haml), :Helpers)
32
32
 
33
+ XML_HELPER = Sexp.new(:colon2, Sexp.new(:const, :Erubis), :XmlHelper)
34
+
33
35
  URI = Sexp.new(:const, :URI)
34
36
 
35
37
  CGI = Sexp.new(:const, :CGI)
@@ -48,7 +50,7 @@ class CheckCrossSiteScripting < BaseCheck
48
50
  @current_template = template
49
51
 
50
52
  template[:outputs].each do |out|
51
- type, match = has_immediate_user_input?(out[1])
53
+ type, match = (out[0] == :output and has_immediate_user_input?(out[1]))
52
54
  if type and not duplicate? out
53
55
  add_result out
54
56
  case type
@@ -102,6 +104,16 @@ class CheckCrossSiteScripting < BaseCheck
102
104
  process exp[1].dup
103
105
  end
104
106
 
107
+ #Look for calls to raw()
108
+ #Otherwise, ignore
109
+ def process_escaped_output exp
110
+ if exp[1].node_type == :call and exp[1][2] == :raw
111
+ process_output exp
112
+ else
113
+ exp
114
+ end
115
+ end
116
+
105
117
  #Check a call for user input
106
118
  #
107
119
  #
@@ -154,6 +166,7 @@ class CheckCrossSiteScripting < BaseCheck
154
166
  (@matched == :model and IGNORE_MODEL_METHODS.include? method) or
155
167
  (target == HAML_HELPERS and method == :html_escape) or
156
168
  ((target == URI or target == CGI) and method == :escape) or
169
+ (target == XML_HELPER and method == :escape_xml) or
157
170
  (target == FORM_BUILDER and IGNORE_METHODS.include? method) or
158
171
  (method.to_s[-1,1] == "?")
159
172
 
@@ -163,7 +176,6 @@ class CheckCrossSiteScripting < BaseCheck
163
176
 
164
177
  @matched = :model
165
178
  elsif @inspect_arguments and (ALL_PARAMETERS.include?(exp) or params? exp)
166
-
167
179
  @matched = :params
168
180
  elsif @inspect_arguments
169
181
  process args
@@ -50,6 +50,8 @@ class Processor
50
50
  result = ErbTemplateProcessor.new(@tracker, name, called_from, file_name).process src
51
51
  when :haml
52
52
  result = HamlTemplateProcessor.new(@tracker, name, called_from, file_name).process src
53
+ when :erubis
54
+ result = ErubisTemplateProcessor.new(@tracker, name, called_from, file_name).process src
53
55
  else
54
56
  abort "Unknown template type: #{type} (#{name})"
55
57
  end
@@ -2,6 +2,7 @@ require 'processors/template_processor'
2
2
 
3
3
  #Processes ERB templates using Erubis instead of erb.
4
4
  class ErubisTemplateProcessor < TemplateProcessor
5
+
5
6
 
6
7
  #s(:call, TARGET, :method, s(:arglist))
7
8
  def process_call exp
@@ -10,10 +11,10 @@ class ErubisTemplateProcessor < TemplateProcessor
10
11
  target = process target
11
12
  end
12
13
  method = exp[2]
13
-
14
+
14
15
  #_buf is the default output variable for Erubis
15
- if target and target[1] == :_buf
16
- if method == :<<
16
+ if target and (target[1] == :_buf or target[1] == :output_buffer)
17
+ if method == :<< or method == :safe_concat
17
18
  args = exp[3][1] = process(exp[3][1])
18
19
 
19
20
  if args.node_type == :call and args[2] == :to_s #just calling to_s on inner code
@@ -59,4 +60,26 @@ class ErubisTemplateProcessor < TemplateProcessor
59
60
  block.line(exp.line)
60
61
  block
61
62
  end
63
+
64
+ #Look for assignments to output buffer
65
+ def process_attrasgn exp
66
+ if exp[1].node_type == :ivar and exp[1][1] == :@output_buffer
67
+ if exp[2] == :append= or exp[2] == :safe_append=
68
+ args = exp[3][1] = process(exp[3][1])
69
+
70
+ if args.node_type == :str
71
+ ignore
72
+ else
73
+ s = Sexp.new :escaped_output, args
74
+ s.line(exp.line)
75
+ @current_template[:outputs] << s
76
+ s
77
+ end
78
+ else
79
+ ignore
80
+ end
81
+ else
82
+ super
83
+ end
84
+ end
62
85
  end
@@ -153,6 +153,23 @@ class OutputProcessor < Ruby2Ruby
153
153
  out
154
154
  end
155
155
 
156
+ def process_escaped_output exp
157
+ out = if exp[0].node_type == :str
158
+ ""
159
+ else
160
+ res = process exp[0]
161
+
162
+ if res == ""
163
+ ""
164
+ else
165
+ "[Escaped Output] #{res}"
166
+ end
167
+ end
168
+ exp.clear
169
+ out
170
+ end
171
+
172
+
156
173
  def process_format exp
157
174
  out = if exp[0].node_type == :str or exp[0].node_type == :ignore
158
175
  ""
@@ -17,6 +17,10 @@ class ScannerErubis < Erubis::Eruby
17
17
  include Erubis::NoTextEnhancer
18
18
  end
19
19
 
20
+ class ErubisEscape < ScannerErubis
21
+ include Erubis::EscapeEnhancer
22
+ end
23
+
20
24
  #Scans the Rails application.
21
25
  class Scanner
22
26
 
@@ -61,7 +65,9 @@ class Scanner
61
65
  @processor.process_config(RubyParser.new.parse(File.read("#@path/config/gems.rb")))
62
66
  end
63
67
 
64
- if File.exists? "#@path/vendor/plugins/rails_xss" or OPTIONS[:rails3]
68
+ if File.exists? "#@path/vendor/plugins/rails_xss" or
69
+ OPTIONS[:rails3] or OPTIONS[:escape_html] or
70
+ (File.exists? "#@path/Gemfile" and File.read("#@path/Gemfile").include? "rails_xss")
65
71
  tracker.config[:escape_html] = true
66
72
  warn "[Notice] Escaping HTML by default"
67
73
  end
@@ -143,8 +149,14 @@ class Scanner
143
149
  begin
144
150
  if type == :erb
145
151
  if tracker.config[:escape_html]
146
- src = RailsXSSErubis.new(File.read(f)).src
152
+ type = :erubis
153
+ if OPTIONS[:rails3]
154
+ src = RailsXSSErubis.new(File.read(f)).src
155
+ else
156
+ src = ErubisEscape.new(File.read(f)).src
157
+ end
147
158
  elsif tracker.config[:erubis]
159
+ type = :erubis
148
160
  src = ScannerErubis.new(File.read(f)).src
149
161
  else
150
162
  src = ERB.new(File.read(f), nil, "-").src
@@ -200,34 +212,49 @@ class Scanner
200
212
  end
201
213
  end
202
214
 
203
- #This is from the rails_xss plugin,
204
- #except we don't care about plain text.
215
+ #This is from Rails 3 version of the Erubis handler
205
216
  class RailsXSSErubis < ::Erubis::Eruby
206
217
  include Erubis::NoTextEnhancer
207
218
 
208
219
  #Initializes output buffer.
209
220
  def add_preamble(src)
210
- src << "@output_buffer = ActionView::SafeBuffer.new;\n"
221
+ # src << "_buf = ActionView::SafeBuffer.new;\n"
211
222
  end
212
223
 
213
224
  #This does nothing.
214
225
  def add_text(src, text)
215
- # src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
226
+ # src << "@output_buffer << ('" << escape_text(text) << "'.html_safe!);"
216
227
  end
217
228
 
218
- #Add an expression to the output buffer _without_ escaping.
229
+ BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
230
+
219
231
  def add_expr_literal(src, code)
220
- src << '@output_buffer << ((' << code << ').to_s);'
232
+ if code =~ BLOCK_EXPR
233
+ src << '@output_buffer.append= ' << code
234
+ else
235
+ src << '@output_buffer.append= (' << code << ');'
236
+ end
237
+ end
238
+
239
+ def add_stmt(src, code)
240
+ if code =~ BLOCK_EXPR
241
+ src << '@output_buffer.append_if_string= ' << code
242
+ else
243
+ super
244
+ end
221
245
  end
222
246
 
223
- #Add an expression to the output buffer after escaping it.
224
247
  def add_expr_escaped(src, code)
225
- src << '@output_buffer << ' << escaped_expr(code) << ';'
248
+ if code =~ BLOCK_EXPR
249
+ src << "@output_buffer.safe_append= " << code
250
+ else
251
+ src << "@output_buffer.safe_concat(" << code << ");"
252
+ end
226
253
  end
227
254
 
228
255
  #Add code to output buffer.
229
256
  def add_postamble(src)
230
- src << '@output_buffer.to_s'
257
+ # src << '_buf.to_s'
231
258
  end
232
259
  end
233
260
 
@@ -1 +1 @@
1
- Version = "0.3.2"
1
+ Version = "0.4.0"
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 2
9
- version: 0.3.2
7
+ - 4
8
+ - 0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Justin Collins
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-05-12 00:00:00 -07:00
17
+ date: 2011-05-18 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency