What Is Brute-Force Attack?
An attack method that tries every possible combination of credentials until the correct one is found. Brute-force attacks target login forms, API keys, encryption keys, and any authentication mechanism that does not limit the number of attempts.
How It Works
A brute-force attack against a Laravel login endpoint works by systematically testing candidate passwords through automation, exploiting the fact that HTTP forms accept unlimited submissions by default.
Step 1: Target identification — The attacker identifies the login endpoint (POST /login) and its required parameters (typically email and password from a standard Laravel form). They also need the CSRF token — in automated attacks, they first request the login page to extract the _token field value from the HTML form.
Step 2: Wordlist preparation — The attacker obtains or prepares wordlists: common passwords (rockyou.txt with 14 million entries), credential pairs from previous data breaches (sold on underground markets), or generated combinations based on the organization name or user's public information (targeted spear attack). Credential stuffing uses email/password pairs from breached databases of other services.
Step 3: Automated iteration — An automated tool (Hydra, Burp Intruder, custom Python script) sends POST requests at the maximum speed the server and network allow — typically hundreds to thousands per second without rate limiting. Each request includes the target email address and the next password candidate from the list. The CSRF token must be refreshed if the session expires.
Step 4: Response analysis — The tool analyzes each HTTP response. A 302 redirect to the dashboard or a 200 response containing the authenticated user's data indicates success. A 422 Unprocessable Entity with form validation errors, or a 200 response containing "These credentials do not match our records," indicates failure. Modern tools handle both patterns automatically.
Step 5: Escalation — With valid credentials, the attacker authenticates normally. If the account has MFA, they are stopped — which is why MFA is the single most effective control against brute-force attacks that succeed in guessing a password.
Types of Brute-Force Attack
Dictionary Attack
Attacker tests a wordlist of common passwords against one or more accounts — the most common form of automated brute-force against web login forms.
# Testing common passwords against one account:
# hydra -l admin@yourapp.com -P /usr/share/wordlists/rockyou.txt yourapp.com http-post-form
# "/login:email=^USER^&password=^PASS^&_token=TOKEN:These credentials"
Credential Stuffing
Attacker uses email/password pairs leaked from other site breaches — effective because many users reuse passwords. Tests at lower rates to avoid detection.
# Credential stuffing: test leaked credential pairs
# email:password pairs from breached database
# POST /login with each pair — success rate 0.1-2% but scales to millions
Password Spraying
Attacker tests one common password (e.g., "Welcome1!") against many accounts — evades per-account lockout policies by staying under the lockout threshold per account.
# Password spraying: one password, many accounts
# Tests "Password123!" against all discovered email addresses
# Never triggers per-account lockout because only 1 attempt per account
In Laravel Applications
Protect Laravel login endpoints with rate limiting (throttle middleware), account lockout after repeated failures, CAPTCHA for suspicious activity, and multi-factor authentication. Laravel Breeze and Fortify include brute-force protection by default.
Code Examples
Login Without vs. With Multi-Layer Brute-Force Protection
Vulnerable
// VULNERABLE: No rate limiting — attacker can attempt 10,000 passwords/second
// routes/web.php
Route::post('/login', [AuthenticatedSessionController::class, 'store'])
->name('login');
// No throttle: 10,000 passwords/sec = 36 million attempts/hour
Secure
// SECURE: Multi-layer brute force protection
// routes/web.php
Route::post('/login', [AuthenticatedSessionController::class, 'store'])
->middleware(['throttle:login'])
->name('login');
// RouteServiceProvider — rate limit by BOTH IP and email
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(5)->by($request->ip()),
Limit::perMinute(3)->by($request->input('email')),
];
});
// EventServiceProvider — log all failures for anomaly detection
protected $listen = [
\Illuminate\Auth\Events\Failed::class => [
\App\Listeners\LogFailedLoginAttempt::class,
],
];
// Enable MFA in Fortify config/fortify.php:
// 'features' => [Features::twoFactorAuthentication()],
Real-World Example
An attacker uses a wordlist of 10,000 common passwords against your /login endpoint. Without rate limiting, all 10,000 attempts complete in minutes.
Why It Matters
Brute-force attacks against Laravel login endpoints are automated, relentless, and constant. Every public-facing login form is being probed continuously by bots using leaked password databases (credential stuffing) and common password wordlists. The question is not whether your application will be targeted, but whether your defenses are sufficient to make the attack impractical.
The most important defense is rate limiting, but it must be configured at the right level. The default throttle:60,1 in many Laravel tutorials is far too permissive. A strict throttle:5,1 on the login route prevents automated attacks from making meaningful progress. Laravel Fortify (laravel/fortify) implements rate limiting that tracks both IP address and email, preventing attackers from rotating IPs to bypass IP-only rate limiting.
Password strength requirements reduce brute-force success rates but are not a primary defense. Rate limiting, account lockout, and multi-factor authentication are more effective because they make the attack impractical regardless of password complexity.
Monitoring is essential for detecting ongoing brute-force attacks. Laravel's Auth::failed event fires on every failed login attempt. Logging this event in EventServiceProvider and aggregating logs externally allows you to detect patterns: thousands of failed attempts for different users from the same IP, or failed attempts for one user from many IPs (distributed brute force).
Common Misconceptions
Myth: Strong password requirements prevent brute-force attacks.
Reality: Strong passwords increase the time required but do not make brute-force impractical without rate limiting. Most modern attacks use leaked passwords from other breaches rather than pure brute force — credential stuffing succeeds even against complex passwords.
Myth: CAPTCHA alone is sufficient to stop brute-force attacks.
Reality: CAPTCHAs are increasingly solved by automated services (paid human solvers, AI-based CAPTCHA breaking). CAPTCHAs should complement, not replace, rate limiting and account lockout.
Myth: Our login endpoint is protected because it is behind Cloudflare.
Reality: Cloudflare provides DDoS protection and WAF rules but does not know that 5 failed logins from one IP is suspicious. Application-level rate limiting with per-user tracking is necessary because Cloudflare cannot apply your business logic.
How to Detect This
Enable logging of failed authentication attempts by registering a listener for `Illuminate\Auth\Events\Failed` in `EventServiceProvider`. Check `storage/logs/laravel.log` for patterns of repeated authentication failures. Run `grep "authentication attempt" storage/logs/laravel.log | wc -l` to count failed attempts and compare against baseline. Use `curl` to verify rate limiting is active: send 10 rapid POST requests to `/login` and confirm a 429 response appears after your configured limit. StackShield probes your login and password reset endpoints as part of external scanning to verify rate limiting is correctly enforced, flagging endpoints that return 200 or 302 responses beyond the expected throttle threshold.
How to Prevent This in Laravel
-
1
Apply `throttle:login` middleware (defined with both IP and email limits in `RateLimiter::for()`) to your `/login` and `/password/email` routes — single-digit per-minute limits for login, 3/minute for password reset.
-
2
Enable two-factor authentication in `config/fortify.php` by adding `Features::twoFactorAuthentication()` to the features array — MFA stops all credential-stuffing attacks even when the password is correct.
-
3
Register a listener for `Illuminate\Auth\Events\Failed` in `EventServiceProvider` that logs the failed email, IP address, and user agent to enable anomaly detection and alerting.
-
4
Set `CACHE_DRIVER=redis` in production `.env` so rate limit counters are shared across all application processes and servers, preventing attackers from rotating between processes to bypass limits.
-
5
Consider implementing progressive delays or CAPTCHA (via `anhskohbo/no-captcha` or `josiasmontag/laravel-recaptchav3`) after 3-5 failed attempts to increase the cost of automated attacks.
Frequently Asked Questions
Does Laravel Fortify include brute-force protection?
Yes — Laravel Fortify includes rate limiting on authentication endpoints by default, configured in `config/fortify.php`. It uses a named rate limiter that limits by both IP address and email address, which prevents attackers from rotating IPs to bypass IP-only limits. It also supports two-factor authentication via the `Features::twoFactorAuthentication()` feature flag, which is the most effective control against brute-force attacks that successfully guess a password.
How do I implement account lockout in Laravel?
Laravel Fortify handles login throttling automatically with the `throttle:login` middleware, which temporarily blocks additional attempts after the configured limit is exceeded. For persistent lockout (blocking an account for hours after repeated failures), listen to `Illuminate\Auth\Events\Failed` events, count failures per email in the cache, and check this count in a custom middleware that runs before the login controller. Unlock accounts via an admin command or after a TTL expiry using `Cache::forget()`.
What is the difference between brute force and credential stuffing?
Pure brute force tries all possible password combinations for one account — impractical for strong passwords. Dictionary attacks test a wordlist of common passwords. Credential stuffing tests email/password pairs leaked from OTHER websites' breaches — effective because 60%+ of users reuse passwords across sites. Credential stuffing is more dangerous because the passwords it tests are real passwords the user has actually used, making success rates much higher than wordlist attacks against randomly generated passwords.
How can I detect an ongoing brute-force attack against my application?
Monitor `storage/logs/laravel.log` for spikes in authentication failure events. Configure `Illuminate\Auth\Events\Failed` listeners to send failures to an external monitoring service with IP and email metadata. Set up an alert when more than 10 failed logins occur per minute from any single IP, or more than 5 failures against any single email address in 10 minutes. StackShield probes your login endpoint periodically and alerts if it accepts rapid sequential requests without returning 429 responses.
Related Terms
Rate Limiting
A technique that controls the number of requests a client can make to a server within a specified time period. Rate limiting protects against brute-force attacks, denial of service, API abuse, and web scraping by rejecting requests that exceed the defined threshold.
DDoS (Distributed Denial of Service)
An attack that overwhelms a server or network with traffic from many sources simultaneously, making it unavailable to legitimate users. Unlike a simple DoS attack from one source, DDoS attacks use thousands of compromised devices (a botnet) to generate traffic that is difficult to filter.
Related Articles
Related Fix Guides
Monitor Your Laravel Application's Security
StackShield continuously checks your Laravel application from the outside, catching security issues before attackers find them.
Start Free Trial