From 70e293ba949a5811b78cbed69aa5610a661271ad Mon Sep 17 00:00:00 2001 From: Benjamin Neff Date: Sat, 15 Jun 2024 03:57:12 +0200 Subject: [PATCH] Add rack-attack to throttle login actions This also fixes CVE-2024-0227 for 2FA brute force See: https://blog.inhq.net/posts/totp-CVE-2024-0227/ --- Changelog.md | 5 +++++ Gemfile | 4 ++++ Gemfile.lock | 3 +++ config/initializers/rack_attack.rb | 26 ++++++++++++++++++++++++++ 4 files changed, 38 insertions(+) create mode 100644 config/initializers/rack_attack.rb diff --git a/Changelog.md b/Changelog.md index 5ad45df9a..37a3d9804 100644 --- a/Changelog.md +++ b/Changelog.md @@ -42,6 +42,11 @@ We recommend setting up new pods using Ruby 3.3, and updating existing pods to t If you're currently running your production pod with `./script/server` in a tmux or something similar, please be careful. We made some internal changes that result in the script no longer automatically restarting the server if it crashes - instead, it will just shut down. We strongly recommend running your pod using your system's unit manager, for example with [this systemd unit](https://wiki.diasporafoundation.org/Automatic_startup_methods#Recommended:_systemd). +## Security + +* Fix a potential 2FA brute force attack ([CVE-2024-0227](https://github.com/devise-two-factor/devise-two-factor/security/advisories/GHSA-chcr-x7hc-8fp8)). + Thanks to Christian Reitter ([Radically Open Security](https://www.radicallyopensecurity.com/)) and Chris MacNaughton ([Centauri Solutions](https://centauri.solutions)). + ## Refactor * Add bootstrapping for using ECMAScript 6 with automatic transpiling for compatibility [#7581](https://github.com/diaspora/diaspora/pull/7581) [#8397](https://github.com/diaspora/diaspora/pull/8397) * Remove backporting of mention syntax [#7788](https://github.com/diaspora/diaspora/pull/7788) diff --git a/Gemfile b/Gemfile index 0c963ad29..9c6ee61b7 100644 --- a/Gemfile +++ b/Gemfile @@ -115,6 +115,10 @@ gem "redcarpet", "3.6.0" gem "ruby-oembed", "0.17.0" gem "twitter-text", "3.1.0" +# Rate limitting + +gem "rack-attack", "6.7.0" + # RTL support gem "string-direction", "1.2.2" diff --git a/Gemfile.lock b/Gemfile.lock index e74d323cd..b34c7b927 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -509,6 +509,8 @@ GEM raabro (1.4.0) racc (1.8.0) rack (2.2.9) + rack-attack (6.7.0) + rack (>= 1.0, < 4) rack-cors (2.0.2) rack (>= 2.0.0) rack-google-analytics (1.2.0) @@ -841,6 +843,7 @@ DEPENDENCIES pry pry-byebug puma (= 6.4.2) + rack-attack (= 6.7.0) rack-cors (= 2.0.2) rack-google-analytics (= 1.2.0) rack-piwik (= 0.3.0) diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb new file mode 100644 index 000000000..fa44652b5 --- /dev/null +++ b/config/initializers/rack_attack.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Rack + class Attack + class Request + def throttleable_ip + parsed = IPAddr.new(ip) + + if parsed.ipv6? && !parsed.ipv4_mapped? + # Throttle all requests from the same /64 IPv6 subnet + parsed.mask(64) + else + parsed + end.to_s + end + end + + throttle("logins/ip", limit: 20, period: 5.minutes) do |req| + req.throttleable_ip if req.post? && req.path.start_with?("/users/sign_in") + end + + throttle("otp/user_id", limit: 20, period: 1.hour) do |req| + req.session[:otp_user_id] if req.post? && req.path.start_with?("/users/sign_in") && req.session[:otp_user_id] + end + end +end