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:
-
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 <tj@vision-media.ca>
Attributes
options[R]
Public Class Methods
new(app, options = {})
click to toggle source
# File lib/rack/contrib/deflect.rb, line 44 def initialize app, options = {} @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(options) end
Public Instance Methods
block!()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 100 def block! return if blocked? log "blocked #{@remote_addr}" map[:block_expires] = Time.now + options[:block_duration] end
block_expired?()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 110 def block_expired? map[:block_expires] < Time.now rescue false end
blocked?()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 106 def blocked? map.has_key? :block_expires end
call(env)
click to toggle source
# 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!()
click to toggle source
# 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!()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 65 def deflect! [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []] end
deflect?(env)
click to toggle source
# File lib/rack/contrib/deflect.rb, line 69 def deflect? env @remote_addr = env['REMOTE_ADDR'] return false if options[:whitelist].include? @remote_addr return true if options[:blacklist].include? @remote_addr sync { watch } end
exceeded_request_threshold?()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 128 def exceeded_request_threshold? map[:requests] > options[:request_threshold] end
increment_requests()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 124 def increment_requests map[:requests] += 1 end
log(message)
click to toggle source
# File lib/rack/contrib/deflect.rb, line 76 def log message return unless options[:log] options[:log].puts(options[:log_format] % [Time.now.strftime(options[:log_date_format]), message]) end
map()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 85 def map @remote_addr_map[@remote_addr] ||= { :expires => Time.now + options[:interval], :requests => 0 } end
sync(&block)
click to toggle source
# File lib/rack/contrib/deflect.rb, line 81 def sync &block @mutex.synchronize(&block) end
watch()
click to toggle source
# 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?()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 132 def watch_expired? map[:expires] <= Time.now end
watching?()
click to toggle source
# File lib/rack/contrib/deflect.rb, line 114 def watching? @remote_addr_map.has_key? @remote_addr end