zammad/config/initializers/rack_attack.rb
2026-01-02 15:41:09 +02:00

53 lines
1.8 KiB
Ruby

# Copyright (C) 2012-2026 Zammad Foundation, https://zammad-foundation.org/
THROTTLE_PUBLIC_ENDPOINTS = [
{
url: '/api/v1/users/password_reset'.freeze,
field: 'username',
},
{
url: '/api/v1/users/email_verify_send'.freeze,
field: 'email',
},
{
url: '/api/v1/users/admin_password_auth'.freeze,
field: 'username',
},
].freeze
THROTTLE_PUBLIC_ENDPOINTS.each do |config|
Rack::Attack.throttle("limit #{config[:url]} requests per #{config[:field]}", limit: 3, period: 1.minute.to_i) do |req|
if req.path.start_with?(config[:url]) && req.post?
# Normalize to protect against rate limit bypasses.
req.params[config[:field]].to_s.downcase.gsub(%r{\s+}, '')
end
end
Rack::Attack.throttle("limit #{config[:url]} requests per source IP address", limit: 3, period: 1.minute.to_i) do |req|
if req.path.start_with?(config[:url]) && req.post?
req.ip
end
end
end
#
# Throttle form submit requests
#
API_V1_FORM_SUBMIT_PATH = '/api/v1/form_submit'.freeze
form_limit_by_ip_per_hour_proc = proc { Setting.get('form_ticket_create_by_ip_per_hour') || 20 }
Rack::Attack.throttle('form submits per IP and hour', limit: form_limit_by_ip_per_hour_proc, period: 1.hour.to_i) do |req|
if req.path.start_with?(API_V1_FORM_SUBMIT_PATH)
req.ip
end
end
form_limit_by_ip_per_day_proc = proc { Setting.get('form_ticket_create_by_ip_per_day') || 240 }
Rack::Attack.throttle('form submits per IP and day', limit: form_limit_by_ip_per_day_proc, period: 1.day.to_i) do |req|
if req.path.start_with?(API_V1_FORM_SUBMIT_PATH)
req.ip
end
end
form_limit_per_day_proc = proc { Setting.get('form_ticket_create_per_day') || 5000 }
Rack::Attack.throttle('form submits per day', limit: form_limit_per_day_proc, period: 1.day.to_i) do |req|
if req.path.start_with?(API_V1_FORM_SUBMIT_PATH)
req.path
end
end