class Rack::Deflect

Rack middleware for protecting against Denial-of-service attacks en.wikipedia.org/wiki/Denial-of-service_attack.

This middleware is designed for small deployments, which most likely are not utilizing load balancing from other software or hardware. Deflect current supports the following functionality:

Options:

:log                When false logging will be bypassed, otherwise pass an object responding to #puts
:log_format         Alter the logging format
:log_date_format    Alter the logging date format
:request_threshold  Number of requests allowed within the set :interval. Defaults to 100
:interval           Duration in seconds until the request counter is reset. Defaults to 5
:block_duration     Duration in seconds that a remote address will be blocked. Defaults to 900 (15 minutes)
:whitelist          Array of remote addresses which bypass Deflect. NOTE: this does not block others
:blacklist          Array of remote addresses immediately considered malicious

Examples:

use Rack::Deflect, :log => $stdout, :request_threshold => 20, :interval => 2, :block_duration => 60

CREDIT: TJ Holowaychuk <tj@vision-media.ca>

Attributes

options[R]

Public Class Methods

new(app, options = {}) click to toggle source
   # File lib/rack/contrib/deflect.rb
46 def initialize app, options = {}
47   @mutex = Mutex.new
48   @remote_addr_map = {}
49   @app, @options = app, {
50     :log => false,
51     :log_format => 'deflect(%s): %s',
52     :log_date_format => '%m/%d/%Y',
53     :request_threshold => 100,
54     :interval => 5,
55     :block_duration => 900,
56     :whitelist => [],
57     :blacklist => []
58   }.merge(options)
59 end

Public Instance Methods

block!(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
102 def block!(remote_addr)
103   return if blocked?(remote_addr)
104   log "blocked #{remote_addr}"
105   map(remote_addr)[:block_expires] = Time.now + options[:block_duration]
106 end
block_expired?(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
112 def block_expired?(remote_addr)
113   map(remote_addr)[:block_expires] < Time.now rescue false
114 end
blocked?(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
108 def blocked?(remote_addr)
109   map(remote_addr).has_key? :block_expires
110 end
call(env) click to toggle source
   # File lib/rack/contrib/deflect.rb
61 def call env
62   return deflect! if deflect? env
63   status, headers, body = @app.call env
64   [status, headers, body]
65 end
clear!(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
120 def clear!(remote_addr)
121   return unless watching?(remote_addr)
122   log "released #{remote_addr}" if blocked?(remote_addr)
123   @remote_addr_map.delete remote_addr
124 end
deflect!() click to toggle source
   # File lib/rack/contrib/deflect.rb
67 def deflect!
68   [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
69 end
deflect?(env) click to toggle source
   # File lib/rack/contrib/deflect.rb
71 def deflect? env
72   remote_addr = env['REMOTE_ADDR']
73   return false if options[:whitelist].include? remote_addr
74   return true  if options[:blacklist].include? remote_addr
75   sync { watch(remote_addr) }
76 end
exceeded_request_threshold?(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
130 def exceeded_request_threshold?(remote_addr)
131   map(remote_addr)[:requests] > options[:request_threshold]
132 end
increment_requests(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
126 def increment_requests(remote_addr)
127   map(remote_addr)[:requests] += 1
128 end
log(message) click to toggle source
   # File lib/rack/contrib/deflect.rb
78 def log message
79   return unless options[:log]
80   options[:log].puts(options[:log_format] % [Time.now.strftime(options[:log_date_format]), message])
81 end
map(remote_addr) click to toggle source
   # File lib/rack/contrib/deflect.rb
87 def map(remote_addr)
88   @remote_addr_map[remote_addr] ||= {
89     :expires => Time.now + options[:interval],
90     :requests => 0
91   }
92 end
sync(&block) click to toggle source
   # File lib/rack/contrib/deflect.rb
83 def sync &block
84   @mutex.synchronize(&block)
85 end
watch(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
 94 def watch(remote_addr)
 95   increment_requests(remote_addr)
 96   clear!(remote_addr) if watch_expired?(remote_addr) and not blocked?(remote_addr)
 97   clear!(remote_addr) if blocked?(remote_addr) and block_expired?(remote_addr)
 98   block!(remote_addr) if watching?(remote_addr) and exceeded_request_threshold?(remote_addr)
 99   blocked?(remote_addr)
100 end
watch_expired?(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
134 def watch_expired?(remote_addr)
135   map(remote_addr)[:expires] <= Time.now
136 end
watching?(remote_addr) click to toggle source
    # File lib/rack/contrib/deflect.rb
116 def watching?(remote_addr)
117   @remote_addr_map.has_key? remote_addr
118 end