diff --git a/apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.ex b/apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.ex new file mode 100644 index 0000000000..733581f8a7 --- /dev/null +++ b/apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.ex @@ -0,0 +1,69 @@ +defmodule TransportWeb.Backoffice.RateLimiterLive do + use Phoenix.LiveView + import TransportWeb.Backoffice.JobsLive, only: [ensure_admin_auth_or_redirect: 3] + import TransportWeb.Router.Helpers, only: [static_path: 2] + import Helpers, only: [format_number: 1] + + @impl true + def mount(_params, %{"current_user" => current_user} = _session, socket) do + {:ok, + ensure_admin_auth_or_redirect(socket, current_user, fn socket -> + if connected?(socket), do: schedule_next_update_data() + + socket + |> assign(%{ + phoenix_ddos_max_2min_requests: env_value_to_int("PHOENIX_DDOS_MAX_2MIN_REQUESTS"), + phoenix_ddos_max_1hour_requests: env_value_to_int("PHOENIX_DDOS_MAX_1HOUR_REQUESTS"), + phoenix_ddos_safelist_ips: env_value_to_list("PHOENIX_DDOS_SAFELIST_IPS"), + phoenix_ddos_blocklist_ips: env_value_to_list("PHOENIX_DDOS_BLOCKLIST_IPS"), + log_user_agent: env_value("LOG_USER_AGENT"), + block_user_agent_keywords: env_value_to_list("BLOCK_USER_AGENT_KEYWORDS"), + allow_user_agents: env_value_to_list("ALLOW_USER_AGENTS") + }) + |> update_data() + end)} + end + + @impl true + def handle_info(:update_data, socket) do + schedule_next_update_data() + {:noreply, update_data(socket)} + end + + defp schedule_next_update_data do + Process.send_after(self(), :update_data, 1000) + end + + defp update_data(socket) do + assign(socket, + last_updated_at: (Time.utc_now() |> Time.truncate(:second) |> to_string()) <> " UTC", + ips_in_jail: ips_in_jail() + ) + end + + @impl true + def handle_event("bail_ip_from_jail", %{"ip" => ip}, socket) do + # See https://github.com/xward/phoenix_ddos/blob/feb07469ce318214cddb8e88ac18b5f94b3e31f2/lib/phoenix_ddos/core/jail.ex#L36 + PhoenixDDoS.Jail.bail_out(ip) + {:noreply, socket} + end + + defp ips_in_jail do + # See https://github.com/xward/phoenix_ddos/blob/master/lib/phoenix_ddos/core/jail.ex + {:ok, keys} = Cachex.keys(:phoenix_ddos_jail) + keys |> Enum.reject(&String.starts_with?(&1, "suspicious_")) + end + + defp env_value(env_value), do: System.get_env(env_value) + + defp env_value_to_int(env_name) do + env_name |> System.get_env("500") |> Integer.parse() |> elem(0) + end + + defp env_value_to_list(env_name) do + case System.get_env(env_name, "") do + "" -> "" + value -> value + end + end +end diff --git a/apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.html.heex b/apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.html.heex new file mode 100644 index 0000000000..851f63ba25 --- /dev/null +++ b/apps/transport/lib/transport_web/live/backoffice/rate_limiter_live.html.heex @@ -0,0 +1,101 @@ +
+
+

Plug

+

+ Le plug qui gère la logique de rate limiting, bloquer ou autoriser des requêtes est dans TransportWeb.Plugs.RateLimiter. +

+

+ Le comptage des requêtes et le blocage d'une adresse IP est effectué par la librairie phoenix_ddos. Le backend est Cachex, qui utilise la RAM. Ainsi un redémarrage de l'application + prod-site + réinitialise les compteurs et les adresses IPs bloquées. +

+ +

Configuration

+

+ Plusieurs variables d'environnement permettent de configurer le fonctionnement. Il faut changer ces variables pour ajuster le comportement puis redémarrer l'application. +

+ +

Volume de requêtes

+
    +
  • + PHOENIX_DDOS_MAX_2MIN_REQUESTS + : nombre de requêtes max autorisée par IP par période de 2 minutes. Valeur actuelle : <%= format_number( + @phoenix_ddos_max_2min_requests + ) %> +
  • +
  • + PHOENIX_DDOS_MAX_1HOUR_REQUESTS + : nombre de requêtes max autorisée par IP par période d'1 heure. Valeur actuelle : <%= format_number( + @phoenix_ddos_max_1hour_requests + ) %> +
  • +
+ +

Adresses IPs autorisées ou bloquées

+ +
    +
  • + PHOENIX_DDOS_SAFELIST_IPS + : liste d'adresses IP toujours autorisées. Les valeurs doivent être séparées par des |. Valeur actuelle : + <%= @phoenix_ddos_safelist_ips %> +
  • +
  • + PHOENIX_DDOS_BLOCKLIST_IPS + : liste d'adresses IP toujours bloquées. Les valeurs doivent être séparées par des |. Valeur actuelle : + <%= @phoenix_ddos_blocklist_ips %> +
  • +
+ +

User-Agents

+ +
    +
  • + LOG_USER_AGENT + : active ou désactive le fait de logguer les user agents. Valeurs possible : true + ou false. Valeur actuelle : <%= @log_user_agent %> +
  • +
  • + ALLOW_USER_AGENTS + : user agents toujours autorisés. Les valeurs doivent être séparées par des |. Valeur actuelle : + <%= @allow_user_agents %> +
  • +
  • + BLOCK_USER_AGENT_KEYWORDS + : user agents toujours bloqués. Les valeurs doivent être séparées par des |. Valeur actuelle : + <%= @block_user_agent_keywords %> +
  • +
+ +

Adresses IPs bloquées

+

+ phoenix_ddos + est la dépendance qui gère l'ajout/le retrait de la jail. +

+ +

+ Personne n'est bloqué actuellement. +

+ +
0}> +

+ Adresses IPs actuellement dans la jail : +

+ +
    + <%= for ip <- @ips_in_jail do %> +
  • + <%= ip %> + +
  • + <% end %> +
+
+

Dernière mise à jour: <%= @last_updated_at %>

+
+
+