Class: Rack::Deflect
- Inherits:
-
Object
- Object
- Rack::Deflect
- Defined in:
- lib/rack/contrib/deflect.rb
Overview
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:
-
Saturation prevention (small DoS attacks, or request abuse)
-
Blacklisting of remote addresses
-
Whitelisting of remote addresses
-
Logging
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 <[email protected]>
Instance Attribute Summary collapse
-
#options ⇒ Object
readonly
Returns the value of attribute options.
Instance Method Summary collapse
- #block! ⇒ Object
- #block_expired? ⇒ Boolean
- #blocked? ⇒ Boolean
- #call(env) ⇒ Object
- #clear! ⇒ Object
- #deflect! ⇒ Object
- #deflect?(env) ⇒ Boolean
- #exceeded_request_threshold? ⇒ Boolean
- #increment_requests ⇒ Object
-
#initialize(app, options = {}) ⇒ Deflect
constructor
A new instance of Deflect.
- #log(message) ⇒ Object
- #map ⇒ Object
- #sync(&block) ⇒ Object
- #watch ⇒ Object
- #watch_expired? ⇒ Boolean
- #watching? ⇒ Boolean
Constructor Details
#initialize(app, options = {}) ⇒ Deflect
Returns a new instance of Deflect.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/rack/contrib/deflect.rb', line 44 def initialize app, = {} @mutex = Mutex.new @remote_addr_map = {} @app, @options = app, { :log => false, :log_format => 'deflect(%s): %s', :log_date_format => '%m/%d/%Y', :request_threshold => 100, :interval => 5, :block_duration => 900, :whitelist => [], :blacklist => [] }.merge() end |
Instance Attribute Details
#options ⇒ Object (readonly)
Returns the value of attribute options.
42 43 44 |
# File 'lib/rack/contrib/deflect.rb', line 42 def @options end |
Instance Method Details
#block! ⇒ Object
100 101 102 103 104 |
# File 'lib/rack/contrib/deflect.rb', line 100 def block! return if blocked? log "blocked #{@remote_addr}" map[:block_expires] = Time.now + [:block_duration] end |
#block_expired? ⇒ Boolean
110 111 112 |
# File 'lib/rack/contrib/deflect.rb', line 110 def block_expired? map[:block_expires] < Time.now rescue false end |
#blocked? ⇒ Boolean
106 107 108 |
# File 'lib/rack/contrib/deflect.rb', line 106 def blocked? map.has_key? :block_expires end |
#call(env) ⇒ Object
59 60 61 62 63 |
# File 'lib/rack/contrib/deflect.rb', line 59 def call env return deflect! if deflect? env status, headers, body = @app.call env [status, headers, body] end |
#clear! ⇒ Object
118 119 120 121 122 |
# File 'lib/rack/contrib/deflect.rb', line 118 def clear! return unless watching? log "released #{@remote_addr}" if blocked? @remote_addr_map.delete @remote_addr end |
#deflect! ⇒ Object
65 66 67 |
# File 'lib/rack/contrib/deflect.rb', line 65 def deflect! [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, ''] end |
#deflect?(env) ⇒ Boolean
69 70 71 72 73 74 |
# File 'lib/rack/contrib/deflect.rb', line 69 def deflect? env @remote_addr = env['REMOTE_ADDR'] return false if [:whitelist].include? @remote_addr return true if [:blacklist].include? @remote_addr sync { watch } end |
#exceeded_request_threshold? ⇒ Boolean
128 129 130 |
# File 'lib/rack/contrib/deflect.rb', line 128 def exceeded_request_threshold? map[:requests] > [:request_threshold] end |
#increment_requests ⇒ Object
124 125 126 |
# File 'lib/rack/contrib/deflect.rb', line 124 def increment_requests map[:requests] += 1 end |
#log(message) ⇒ Object
76 77 78 79 |
# File 'lib/rack/contrib/deflect.rb', line 76 def log return unless [:log] [:log].puts([:log_format] % [Time.now.strftime([:log_date_format]), ]) end |
#map ⇒ Object
85 86 87 88 89 90 |
# File 'lib/rack/contrib/deflect.rb', line 85 def map @remote_addr_map[@remote_addr] ||= { :expires => Time.now + [:interval], :requests => 0 } end |
#sync(&block) ⇒ Object
81 82 83 |
# File 'lib/rack/contrib/deflect.rb', line 81 def sync &block @mutex.synchronize(&block) end |
#watch ⇒ Object
92 93 94 95 96 97 98 |
# File 'lib/rack/contrib/deflect.rb', line 92 def watch increment_requests clear! if watch_expired? and not blocked? clear! if blocked? and block_expired? block! if watching? and exceeded_request_threshold? blocked? end |
#watch_expired? ⇒ Boolean
132 133 134 |
# File 'lib/rack/contrib/deflect.rb', line 132 def watch_expired? map[:expires] <= Time.now end |
#watching? ⇒ Boolean
114 115 116 |
# File 'lib/rack/contrib/deflect.rb', line 114 def watching? @remote_addr_map.has_key? @remote_addr end |