Strait
Strait is a rate-limiting library designed to provide security you don't need to think about. Whenever you have code to protect, put a Strait in front of it.
It strikes an excellent balance between accuracy and memory usage, with a default accuracy of 1/60th of the limit period.
Installation
Add this line to your application's Gemfile:
gem 'strait'
And then execute:
$ bundle
Or install it yourself as:
$ gem install strait
Usage
Let's say you have a Rails controller with a lot of DoS attack potential.
class SecureThingController
def do_a_scare
# Does some heavy work that could open it to a DoS attack!
end
end
Well dang, that's no good. Anybody could send thousands of requests to this and take your entire site down, right as you're meeting with an important investor!
Let's put a Strait in front of it!
class SecureThingController
ScareLimiter = Strait.new('do_a_scare') do
limit 5, per: 1.minute
end
rescue_from Strait::RateLimitExceeded do
render :rate_limit_exceeded
end
def do_a_scare
ScareLimiter.limit!(current_user)
# Does heavy work, but only if the user hasn't exceeded their rate limit!
end
end
Viola, just like that, we've got rate limiting. Now a user is limited to 5 per minute!
Accuracy
To understand why Strait isn't perfectly accurate, we should understand how it's implemented. Strait is based on the bucketed-log pattern made popular by Figma, which chooses lower memory usage over perfect accuracy. Despite this decreased accuracy, it fails secure, and should have enough accuracy to not be noticed.
Each rate limiter stores data as a set of N buckets per period. For example, with 10 buckets and a 1-hour period, each bucket covers 6 minutes. To check the limit, we sum all buckets which overlap the last hour. If the buckets are large (like 6 minutes) this can be up to one bucket longer than the period, resulting in a longer block than 100% accuracy.
The default accuracy in Strait is 60 buckets per period. For a 1-hour period, this is up to 1 minute of inaccuracy. For a 1-minute period, it's up to 1-second. For a 1-day period, it's up to 24 minutes. You can adjust this to increase accuracy, but it will also use more memory.
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/hummingbird-me/strait.
License
The gem is available as open source under the terms of the Apache-2.0 License.