bot-away 1.0.3 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,12 @@
1
+ === 1.1.0 2010-06-21
2
+ * Minor enhancements:
3
+ * ActionController::Request.accepts_unfiltered_params is now accessible as BotAway.accepts_unfiltered_params
4
+ * BotAway.show_honeypots = true will show honeypots as visible elements within the form, for debugging.
5
+ * BotAway.dump_params = true will dump the params hash as it was before BotAway modified it, for debugging.
6
+ * BotAway will no longer generate hashes for, or disguise, elements whose names have been added to
7
+ BotAway.unfiltered_params. This should resolve issues where JavaScript is involved (case in point:
8
+ CalendarDateSelect).
9
+
1
10
  === 1.0.3 2010-06-13
2
11
  * Bugfixes:
3
12
  * Resolved: On or before Rails 2.3.8, honeypots were generated as escaped HTML. This was because Rails started
@@ -50,10 +50,10 @@ here's a brief run-down of what's going on:
50
50
 
51
51
  * I feel this library has been fairly well-tested (99.5% test coverage as of this writing), but if you discover a bug
52
52
  and can't be bothered to let me know about it (or you just don't have time to wait for a fix or fix it yourself),
53
- then you can simply add the name of the offending form element to the ActionController::Request.unfiltered_params
53
+ then you can simply add the name of the offending form element to the BotAway.unfiltered_params
54
54
  array like so:
55
- ActionController::Request.accepts_unfiltered_params 'role_ids'
56
- ActionController::Request.accepts_unfiltered_params 'user' # this can be called multiple times
55
+ BotAway.accepts_unfiltered_params 'role_ids'
56
+ BotAway.accepts_unfiltered_params 'user' # this can be called multiple times
57
57
  You should also take note that this is an array, not a hash. So if you have a user[role_ids] as well as a
58
58
  group[role_ids], the +role_ids+ will not be matched on EITHER of these models.
59
59
 
@@ -77,6 +77,25 @@ In your Rails config/environment.rb:
77
77
 
78
78
  That's it.
79
79
 
80
+ == OPTIONAL CONFIGURATION:
81
+
82
+ In general, there's not much to the configuration of Bot-Away. Most options are here for your debugging pleasure, in
83
+ case something isn't quite working as you'd expected and Bot-Away seems to be a potential cause. To set a configuration
84
+ option, you should do so from a Rails initializer -- just create a file with any name (ending with ".rb", of course)
85
+ in your config/initializers directory, and it'll get run during server start-up. Configuration options available to you
86
+ for Bot-Away are as follows:
87
+
88
+ BotAway.accepts_unfiltered_params "name_of_param", "name_of_another_param"
89
+ # Causes the specified parameter to NOT be filtered. If, for instance, "role_ids" is given, then parameters such as
90
+ # user[role_ids], group[role_ids], etc. will not be processed by Bot-Away.
91
+ BotAway.show_honeypots = true
92
+ # Causes Bot-Away to NOT disguise honeypots with CSS or any other technique. This will cause honeypot elements to
93
+ # be displayed on your page. Not ideal for production, but helpful for debugging browser auto-fill issues.
94
+ BotAway.dump_params = true
95
+ # Probably a major security risk in a production application, but again useful in development for gaining insight
96
+ # into what, exactly, is being passed by the browser into Rails before Bot-Away does its thing. If you're getting
97
+ # false positives, this may prove helpful in figuring out why.
98
+
80
99
  == LICENSE:
81
100
 
82
101
  (The MIT License)
@@ -12,7 +12,29 @@ require 'bot-away/action_view/helpers/instance_tag'
12
12
  require 'bot-away/spinner'
13
13
 
14
14
  module BotAway
15
- VERSION = '1.0.3'
15
+ VERSION = '1.1.0'
16
+
17
+ class << self
18
+ attr_accessor :show_honeypots, :dump_params
19
+
20
+ def unfiltered_params(*args)
21
+ ActionController::Request.unfiltered_params(*args)
22
+ end
23
+
24
+ alias accepts_unfiltered_params unfiltered_params
25
+
26
+ def excluded?(object_name, method_name)
27
+ unfiltered_params.collect! { |u| u.to_s }
28
+ if (object_name &&
29
+ (unfiltered_params.include?(object_name.to_s) ||
30
+ unfiltered_params.include?("#{object_name}[#{method_name}]")) ||
31
+ unfiltered_params.include?(method_name.to_s))
32
+ true
33
+ else
34
+ false
35
+ end
36
+ end
37
+ end
16
38
  end
17
39
 
18
40
  # WHY do I have to do this???
@@ -3,7 +3,8 @@ class ActionView::Helpers::InstanceTag
3
3
 
4
4
  def initialize_with_spinner(object_name, method_name, template_object, object = nil)
5
5
  initialize_without_spinner(object_name, method_name, template_object, object)
6
- if template_object.controller.send(:protect_against_forgery?)
6
+ if template_object.controller.send(:protect_against_forgery?) && !BotAway.excluded?(object_name, method_name)
7
+ puts "#{object_name.inspect} => #{method_name.inspect}"
7
8
  @spinner = BotAway::Spinner.new(template_object.request.ip, object_name, template_object.form_authenticity_token)
8
9
  end
9
10
  end
@@ -29,7 +30,7 @@ class ActionView::Helpers::InstanceTag
29
30
  yield if object
30
31
  object
31
32
  end
32
-
33
+
33
34
  def honeypot_tag(name, options = nil, *args)
34
35
  tag_without_honeypot(name, honeypot_options(options.dup? || {}), *args)
35
36
  end
@@ -84,6 +85,7 @@ class ActionView::Helpers::InstanceTag
84
85
  alias_method_chain :content_tag, :obfuscation
85
86
 
86
87
  def disguise(element)
88
+ return element.replace("Honeypot(#{element})") if BotAway.show_honeypots
87
89
  case rand(3)
88
90
  when 0 # Hidden
89
91
  element.replace "<div style='display:none;'>Leave this empty: #{element}</div>"
@@ -4,6 +4,7 @@ module BotAway
4
4
 
5
5
  def initialize(ip, params, authenticity_token = params[:authenticity_token])
6
6
  @ip, @params, @authenticity_token = ip, params, authenticity_token
7
+ Rails.logger.debug(params.inspect) if BotAway.dump_params
7
8
  if authenticity_token
8
9
  if catch(:bastard) { deobfuscate! } == :took_the_bait
9
10
  params.clear
@@ -18,7 +19,7 @@ module BotAway
18
19
  end
19
20
 
20
21
  current.each do |key, value|
21
- if object_name && !value.kind_of?(Hash) && !ActionController::Request.unfiltered_params.include?(key)
22
+ if object_name && !value.kind_of?(Hash) && !BotAway.excluded?(object_name, key)
22
23
  if value.blank? && params.keys.include?(spun_key = spinner.encode("#{object_name}[#{key}]"))
23
24
  current[key] = params.delete(spun_key)
24
25
  else
@@ -33,7 +33,7 @@ describe ActionView::Helpers::InstanceTag do
33
33
  context "with a valid input type=text tag" do
34
34
  before(:each) { @tag_options = ["input", {:type => 'text', 'name' => 'object_name[method_name]', 'id' => 'object_name_method_name', 'value' => 'method_value'}] }
35
35
  #subject { dump { default_instance_tag.tag(*@tag_options) } }
36
-
36
+
37
37
  it "should turn off autocomplete for honeypots" do
38
38
  subject.honeypot_tag(*@tag_options).should =~ /autocomplete="off"/
39
39
  end
@@ -14,7 +14,22 @@ describe ActionView::Helpers::FormBuilder do
14
14
  it "should not create honeypots with default values" do
15
15
  builder.text_field(:method_name).should match(/name="object_name\[method_name\]"[^>]*?value=""/)
16
16
  end
17
-
17
+
18
+ context "with BotAway.show_honeypots == true" do
19
+ before(:each) { BotAway.show_honeypots = true }
20
+ after(:each) { BotAway.show_honeypots = false }
21
+
22
+ it "should not disguise honeypots" do
23
+ builder.text_area(method_name).should_not match(/<\/div>/)
24
+ end
25
+ end
26
+
27
+ it "should not obfuscate names that have been explicitly ignored" do
28
+ BotAway.accepts_unfiltered_params 'method_name'
29
+ builder.text_field('method_name').should_not match(/name="a0844d45bf150668ff1d86a6eb491969/)
30
+ BotAway.unfiltered_params.delete 'method_name'
31
+ end
32
+
18
33
  # select(method, choices, options = {}, html_options = {})
19
34
  obfuscates(:select) { builder.select(:method_name, {1 => :a, 2 => :b }) }
20
35
 
@@ -14,6 +14,17 @@ describe BotAway::ParamParser do
14
14
  end
15
15
 
16
16
  subject { r = BotAway::ParamParser.new(@ip, @params); puts r.params.to_yaml; r }
17
+
18
+ context "with dump_params == true" do
19
+ before(:each) { BotAway.dump_params = true }
20
+ after(:each) { BotAway.dump_params = false }
21
+
22
+ it "should dump params as debug to Rails logger" do
23
+ @params = { 'test' => "hello", :posts => [1] }
24
+ Rails.logger.should_receive(:debug).with(@params.inspect)
25
+ subject
26
+ end
27
+ end
17
28
 
18
29
  context "with blank honeypots" do
19
30
  it "drops obfuscated params" do
@@ -6,7 +6,11 @@ class HoneypotMatcher
6
6
  def matches?(target)
7
7
  target = target.call if target.kind_of?(Proc)
8
8
  @target = target
9
- @rx = /name="#{Regexp::escape @object_name}\[#{Regexp::escape @method_name}/m
9
+ if @method_name.nil?
10
+ @rx = /name="#{Regexp::escape @object_name}/m
11
+ else
12
+ @rx = /name="#{Regexp::escape @object_name}\[#{Regexp::escape @method_name}/m
13
+ end
10
14
  @target[@rx]
11
15
  end
12
16
 
@@ -24,12 +24,23 @@ module ObfuscationHelper
24
24
  @builder = ActionView::Helpers::FormBuilder.new(:object_name, MockObject.new, response.template, {}, proc {})
25
25
  end
26
26
 
27
- def obfuscates(method, obfuscated_id = self.obfuscated_id, obfuscated_name = self.obfuscated_name)
27
+ def obfuscates(method, options = {}, unused = nil)
28
+ if !options.kind_of?(Hash)
29
+ options = { :obfuscated_id => options, :obfuscated_name => unused }
30
+ end
31
+
32
+ obfuscated_id = options[:obfuscated_id] || self.obfuscated_id
33
+ obfuscated_name = options[:obfuscatd_name] || self.obfuscated_name
34
+
28
35
  value = yield
29
36
  context "##{method}" do
30
37
  subject { proc { dump { value } } }
31
38
 
32
- includes_honeypot(object_name, method_name)
39
+ if options[:name]
40
+ includes_honeypot(options[:name], nil)
41
+ else
42
+ includes_honeypot(options[:object_name] || object_name, options[:method_name] || method_name)
43
+ end
33
44
  is_obfuscated_as(obfuscated_id, obfuscated_name)
34
45
  end
35
46
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 1
7
+ - 1
7
8
  - 0
8
- - 3
9
- version: 1.0.3
9
+ version: 1.1.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Colin MacKenzie IV
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-13 00:00:00 -04:00
17
+ date: 2010-06-21 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency