Brute Force Attack in Phoenix
How Brute Force Attacks Manifest in Phoenix
Brute force attacks in Phoenix applications typically target authentication endpoints, API routes, and session management mechanisms. Phoenix's default setup provides several attack surfaces that malicious actors can exploit to systematically guess credentials or sensitive tokens.
The most common attack vector is the login endpoint. Phoenix's default authentication flow, especially when using libraries like Phoenix.Token or Comeonin for password hashing, can become vulnerable when rate limiting isn't implemented. Attackers can send thousands of authentication requests per minute, cycling through common passwords or using credential stuffing techniques with leaked username/password combinations.
Session fixation attacks represent another Phoenix-specific vulnerability. Since Phoenix uses ETS (Erlang Term Storage) for session storage by default, an attacker who can predict or obtain session IDs can hijack user sessions. Without proper session rotation and timeout configurations, brute force attempts can extend beyond login to session token guessing.
API endpoints in Phoenix applications often lack authentication or use weak token validation. When Phoenix applications expose administrative endpoints or sensitive data through JSON APIs without proper rate limiting, attackers can brute force API keys, JWT tokens, or other authentication mechanisms. The Phoenix.Controller module's plug pipeline makes it easy to add authentication, but many developers forget to secure every route.
Phoenix Channels present a unique attack surface. Real-time features using Phoenix Channels can be targeted for brute force attacks on channel authentication tokens or presence system exploits. The Phoenix.Channel module's authorization callbacks, if not properly rate limited, can be overwhelmed with connection attempts.
Another Phoenix-specific concern involves Ecto queries in authentication contexts. When login attempts trigger database queries without proper timing protection, attackers can use timing attacks to determine valid usernames before attempting password brute force. The difference in response time between valid and invalid usernames can leak information.
Phoenix-Specific Detection
Detecting brute force attacks in Phoenix applications requires monitoring both application-level metrics and network traffic patterns. Phoenix's built-in telemetry and instrumentation provide the foundation for effective detection.
Monitoring authentication endpoint traffic is critical. Using Phoenix's telemetry events, you can track [:phoenix, :error_rendered] and [:phoenix, :request_completed] events to identify unusual patterns. A sudden spike in failed authentication attempts from the same IP address or geographic region indicates a brute force attack in progress.
Rate limiting implementation is essential for Phoenix applications. The Phoenix.RateLimiter plug (available in Phoenix 1.7+) allows you to limit requests per IP address. Without this, attackers can send unlimited requests to your login endpoint. Monitoring the [:phoenix, :rate_limited] telemetry event helps identify when legitimate users are being blocked versus when attackers are being throttled.
Session analysis reveals brute force attempts on session tokens. Phoenix's default session implementation stores data in ETS, which is fast but doesn't provide built-in rate limiting. Monitoring session creation and validation patterns using :telemetry hooks on Plug.Session can identify when an attacker is cycling through session IDs.
Database query monitoring helps detect timing attacks. Using Ecto's telemetry events like [:my_app, :repo, :query], you can monitor the duration of authentication-related queries. Consistently longer response times for certain queries might indicate that an attacker is using timing differences to enumerate valid accounts.
Phoenix Channels require specific monitoring. The Phoenix.Channel module emits [:phoenix, :channel_joined] events that you can track to identify unusual connection patterns. Multiple rapid connection attempts to the same channel from different sources might indicate a brute force attack on channel authentication.
middleBrick's scanner specifically tests Phoenix applications for brute force vulnerabilities by simulating authentication attempts and analyzing response patterns. The scanner checks for rate limiting implementation, session management security, and API endpoint protection without requiring access to source code or credentials.
Phoenix-Specific Remediation
Remediating brute force vulnerabilities in Phoenix applications requires a multi-layered approach using Phoenix's native security features and Elixir's concurrency advantages.
Implementing rate limiting at the controller level is the first defense. Phoenix 1.7+ includes the Phoenix.RateLimiter plug that you can add to your authentication pipeline:
defmodule MyAppWeb.AuthController do
use MyAppWeb, :controller
plug :put_root_layout, {MyAppWeb.LayoutView, "app.html"}
# Limit to 5 requests per minute per IP
plug Phoenix.RateLimiter,
bucket: {MyAppWeb.RateLimit, :auth_attempts},
rate: 5,
period: 60_000
def login(conn, %{"session" => session_params}) do
# authentication logic
end
end
The rate limiter uses a token bucket algorithm implemented with Erlang's :persistent_term or ETS, providing efficient in-memory rate limiting without database overhead.
Strengthening password handling with proper hashing and salting is crucial. Phoenix applications should use Comeonin or Argon2 for password hashing:
defmodule MyApp.Accounts do
alias Comeonin.Argon2
def register_user(attrs) do
%User{}
|> User.changeset(attrs)
|> Ecto.Changeset.apply_action(:insert)
end
def authenticate_user(email, password) do
user = Accounts.get_user_by_email(email)
if user && Argon2.check_pass(user, password) do
{:ok, user}
else
# Always perform hash check to prevent timing attacks
Argon2.check_pass(%User{}, "dummy")
{:error, :invalid_credentials}
end
end
end
The key security practice here is performing a hash check even for invalid credentials, ensuring constant-time execution to prevent timing attacks.
Implementing account lockout policies prevents sustained brute force attacks. You can track failed attempts using ETS or an external service:
defmodule MyApp.Accounts do
@max_attempts 5
@lockout_period 15 * 60_000 # 15 minutes
def validate_login(email, password) do
user = get_user_by_email(email)
case check_attempts(email) do
{:locked, _} ->
{:error, :account_locked}
{:ok, attempts} ->
result = authenticate_user(user, password)
case result do
{:ok, user} ->
reset_attempts(email)
{:ok, user}
{:error, _} ->
update_attempts(email, attempts + 1)
if attempts + 1 >= @max_attempts do
lock_account(email)
{:error, :account_locked}
else
{:error, :invalid_credentials}
end
end
end
end
end
Phoenix Channels require specific security measures. Implement proper channel authorization and rate limiting:
defmodule MyAppWeb.UserSocket do
use Phoenix.Socket
channel "room:*", MyAppWeb.RoomChannel
def connect(%{"token" => token}, _params, _socket) do
case Phoenix.Token.verify(socket, "user socket", token) do
{:ok, user_id} ->
{:ok, assign(socket, :user_id, user_id)}
{:error, _reason} ->
:error
end
end
end
Adding exponential backoff to authentication attempts significantly increases the cost of brute force attacks:
defmodule MyAppWeb.AuthController do
use Phoenix.Controller
def login(conn, %{"session" => session_params}) do
# Check if this IP is in exponential backoff
case check_backoff(conn.remote_ip) do
{:blocked, remaining} ->
send_resp(conn, 429, "Too many attempts")
{:ok, wait_time} ->
# Process authentication
result = authenticate_user(session_params)
if result == :error do
# Increase backoff exponentially
increase_backoff(conn.remote_ip)
end
result
end
end
end
Finally, implement comprehensive logging and monitoring using Phoenix's telemetry system to detect and respond to brute force attempts in real-time. The :telemetry library allows you to emit custom events for authentication failures, which can trigger alerts or automated responses.
Frequently Asked Questions
How can I detect if my Phoenix application is being targeted by a brute force attack?
Monitor your Phoenix application's authentication endpoints for unusual traffic patterns using telemetry events. Look for spikes in [:phoenix, :request_completed] events with status: 401 or status: 403 from the same IP addresses. Phoenix's built-in Phoenix.RateLimiter plug will emit [:phoenix, :rate_limited] events when requests are blocked. Additionally, track failed login attempts in your database or ETS tables and set up alerts when the rate exceeds normal thresholds. middleBrick's scanner can proactively test your Phoenix application for brute force vulnerabilities by simulating attack patterns and checking for proper rate limiting implementation.
What's the most effective way to prevent brute force attacks on Phoenix Channels?
Phoenix Channels require a defense-in-depth approach. First, implement proper channel authorization in the Phoenix.Channel module's authorize! callback to ensure only authenticated users can join channels. Second, use Phoenix's Phoenix.RateLimiter plug at the socket level to limit connection attempts per IP address. Third, implement token-based authentication with Phoenix.Token that includes expiration and verification. Fourth, consider using presence tracking to monitor unusual connection patterns. Finally, add custom telemetry monitoring for [:phoenix, :channel_joined] events to detect and block suspicious connection patterns. The combination of these techniques makes brute force attacks on Phoenix Channels significantly more difficult and resource-intensive for attackers.