Credential Stuffing in Hanami (Ruby)
Credential Stuffing in Hanami with Ruby
Hanami, a lightweight web framework for Ruby, can be vulnerable to credential stuffing when its authentication mechanisms are implemented without proper rate limiting or credential throttling. Since Hanami does not include built-in authentication by default, developers often implement custom solutions using Rack middleware or third-party gems. When these implementations lack sufficient protection, attackers can automate login attempts across multiple endpoints using credential lists obtained from prior data breaches, exploiting the framework’s simplicity to test large volumes of username/password combinations.
For example, a typical Hanami controller action for login might directly compare submitted credentials against a database without any throttling:
# apps/web/controllers/auth/login.rb
class Auth::LoginController < Hanami::Controller
include Hanami::Validations
def create
user = UserRepository.find_by(email: params[:email])
if user && BCrypt::Password.new(user.encrypted_password) == params[:password]
session[:user_id] = user.id
redirect_to '/dashboard'
else
flash[:error] = 'Invalid credentials'
redirect_back
end
end
end
This code has no rate limiting, no lockout after failed attempts, and no CAPTCHA or behavioral analysis. As a result, an attacker can script thousands of requests against the /auth/login endpoint using credentials from sources like the Have I Been Pwned database. Because Hanami applications are often deployed behind reverse proxies or on modest infrastructure, there may be no additional WAF or DDoS protection to absorb such traffic.
Credential stuffing attacks against Hanami apps are particularly effective when:
- Multiple independent endpoints accept login parameters (e.g.,
/auth/login,/sign_in,/authenticate) - Password reset or registration endpoints lack progressive throttling
- User enumeration is possible through differential error messages (e.g., “Invalid email” vs “Invalid password”)
These conditions align with the OWASP API Top 10 category A04:2023 - Insecure Design, specifically around insufficient security controls during authentication. Without proactive defenses, Hanami applications are exposed to automated credential stuffing at scale.
Ruby-Specific Remediation in Hanami
To mitigate credential stuffing in Hanami applications using Ruby, developers must implement rate limiting, account lockout, and response uniformity at the application level. Since Hanami does not provide built-in security controls, these protections must be added via Rack middleware or dedicated gems like rack-attack. Below is a correct Ruby implementation using rack-attack to secure the login endpoint.
# config/initializers/rack_attack.rb
Rack::Attack.defer = false
Rack::Attack.throttle "login throttling",
limit: 5,
period: 1.minute,
receptors: [Rack::Attack::Throttle::IPReceptor.new]
Rack::Attack.on_throttled_response = (
env -> response
) do |response|
if response.throttled?
response.status = 429
response.headers["Retry-After"] = "60 seconds"
response.body = { error: "Too many login attempts. Please try again later." }.to_json
end
end
# apps/web/controllers/auth/login.rb
class Auth::LoginController < Hanami::Controller
include Hanami::Validations
def create
user = UserRepository.find_by(email: params[:email])
unless user
fail_with 401, "Invalid credentials"
end
unless BCrypt::Password.new(user.encrypted_password) == params[:password]
fail_with 401, "Invalid credentials"
end
session[:user_id] = user.id
redirect_to '/dashboard'
end
private
def fail_with(status)
response.status = status
response.format :json
response.body = { error: "Invalid credentials" }.to_json
end
end
This code introduces two critical protections:
- Throttling by IP: Only 5 login attempts per minute per IP address are allowed, blocking automated credential stuffing scripts.
- Uniform error responses: Both invalid email and invalid password return the same generic message, preventing user enumeration.
Additionally, pairing this with HTTPS enforcement and multi-factor authentication (MFA) significantly reduces risk. Developers should also integrate monitoring to detect spikes in login failures, which may indicate ongoing attack attempts.