Nexaas::Throttle

Build Status Test Coverage Code Climate

A configurable Rails engine that provides a common way of reducing API abuse, throttling consumers' requests and blocking undesired pentesters and robots.

Installation

Add this line to your application's Gemfile:

gem 'nexaas-throttle'

And then execute:

$ bundle

Or install it yourself as:

$ gem install nexaas-throttle

Usage

In a Rails initializer file such as config/initializers/nexaas_throttle.rb, put something like this:

require "nexaas/throttle"

Nexaas::Throttle.configure do |config|
  config.throttle = true
  config.track = true
  config.period = 1.minute
  config.limit = 2
  config.request_identifier = MyRequestIdentifier
  config.redis_options = {
    host: "localhost",
    port: 6379,
    db: 0,
    namespace: "nexaas:throttle"
  }
  config.ignored_user_agents = [/[Gg]oogle/, /Amazon/]
  config.assets_extensions = %w[bmp tiff css js jpg jpeg png gif woff ttf svg]
end

Configuration

Option Description Default
throttle Whether or not requests are throttled. true
track Whether or not requests are tracked. true
period The size of the throttle window. 1 minute
limit How many requests a consumer can do during a window until he starts being throttled. 60 requests
request_identifier The class that will handle request identification. See Request Identification for more details. nil
redis_options Redis hash configuration where requests counters are persisted.

{
  host: "localhost",
  port: 6379,
  db: 0,
  namespace: "nexaas:throttle"
}
ignored_user_agents An array of User Agents that should be ignored by the throttler. Values are regexes that will be matched against the request User-Agent nil
assets_extensions An array of file extensions considered to be asset-related. Values are strings that will be matched against the request path. Paths that match will be not be throttled %w[css js jpg jpeg png gif woff ttf svg]

Request Identification

Nexaas::Throttle doesn't know how to identify a consumer. Some applications might rely on request IP, others on an API TOKEN. You must provide a way of getting an unique token that identify a request consumer.

If there is no token, the request will go through and won't be accounted for.

Nexaas::Throttle do this by providing a configuration request_identifier, a class where your application would keep the logic that identifies a consumer. This class must have the following interface:

class MyRequestIdentifier
  def initialize(request)
    @request = request
  end

  def token
    @request.ip
    # or @request.env["HTTP_AUTHORIZATION"]
    # or User.find_by(token: @request.params[:token])
    # or Cache.read(@request.params[:token])
  end
end

Tracking requests

In order to track your requests, you must subscribe to a event triggered by Rack::Attack gem as below:

ActiveSupport::Notifications.subscribe("rack.attack") do |name, start, finish, request_id, request|
  if request.env["rack.attack.matched"] == "nexaas/track" && request.env["rack.attack.match_type"] == :track
    # Put your tracking logic here
    # You can use request.env["nexaas.token"] to obtain the token provided by your request_identifier
  end
end

If you want, you can access the request token by inspecting request.env["nexaas.token"]. This is the token your request_identifier provided after evaluating the request.

Response headers

Rate limit headers are available for all request responses and provide information for API users. They are the following:

"X-RateLimit-Limit"     # Total of requests allowed until next reset.
"X-RateLimit-Remaining" # Amount of requests the user can still send before being throttled.
"X-RateLimit-Reset"     # Epoch time for the reset of the request count.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/myfreecomm/nexaas-throttle.

License

The gem is available as open source under the terms of the MIT License.