Cybersecurity

API Security: The Attack That Almost Got Through

December 28, 2024 3 min read By Amey Lokare

🚨 The Attack

It started with unusual traffic patterns. My API was getting hammered with requests from a single IP. Then I noticed authentication attempts—thousands of them.

Someone was trying to break into my system.

The attack: Brute force authentication, rate limit bypass attempts, and SQL injection probes. Here's what happened.

📊 What I Detected

1. Brute Force Authentication

10,000+ login attempts in one hour from a single IP. They were trying common passwords.

2. Rate Limit Bypass

They rotated IPs to bypass rate limits. Used proxies and VPNs.

3. SQL Injection Probes

Attempted SQL injection in API parameters. Classic attack patterns.

4. Directory Traversal

Tried to access files outside the web root using path traversal.

✅ How I Detected It

1. Log Monitoring

I noticed unusual patterns in Laravel logs:

// Unusual pattern: many 401 responses
[2024-12-28 10:00:00] Failed login attempt: user@example.com
[2024-12-28 10:00:01] Failed login attempt: admin@example.com
[2024-12-28 10:00:02] Failed login attempt: test@example.com
// ... thousands more

2. Rate Limiting Alerts

My rate limiter was triggering constantly. That was the first red flag.

3. Failed Authentication Counts

I track failed authentication attempts. The count spiked dramatically.

🛡️ What I Fixed

1. Enhanced Rate Limiting

Implemented stricter rate limits with IP-based and user-based tracking:

// Laravel rate limiting
Route::middleware(['throttle:5,1'])->group(function () {
    Route::post('/login', [AuthController::class, 'login']);
});

// Custom rate limiter
RateLimiter::for('login', function (Request $request) {
    return Limit::perMinute(5)->by($request->ip());
});

2. Account Lockout

Lock accounts after multiple failed attempts:

if ($failedAttempts >= 5) {
    $user->locked_until = now()->addMinutes(30);
    $user->save();
    throw new AccountLockedException('Account locked due to too many failed attempts');
}

3. IP Blocking

Block IPs that show attack patterns:

// Track suspicious IPs
$suspiciousIPs = Cache::remember("suspicious_ips", 3600, function () {
    return DB::table('failed_logins')
        ->select('ip')
        ->where('created_at', '>', now()->subHour())
        ->groupBy('ip')
        ->havingRaw('COUNT(*) > 100')
        ->pluck('ip');
});

// Block in middleware
if ($suspiciousIPs->contains($request->ip())) {
    abort(403, 'IP blocked due to suspicious activity');
}

4. Input Validation

Strict input validation to prevent injection attacks:

$request->validate([
    'email' => 'required|email|max:255',
    'password' => 'required|string|min:8',
]);

5. Security Headers

Added security headers:

// In middleware
return $next($request)
    ->header('X-Content-Type-Options', 'nosniff')
    ->header('X-Frame-Options', 'DENY')
    ->header('X-XSS-Protection', '1; mode=block')
    ->header('Strict-Transport-Security', 'max-age=31536000');

📊 Attack Statistics

Attack Type Attempts Blocked Status
Brute Force 10,000+ 100% ✅ Blocked
SQL Injection 500+ 100% ✅ Blocked
Path Traversal 200+ 100% ✅ Blocked

💡 Security Lessons

  1. Monitor logs: Regular log review catches attacks early
  2. Rate limiting: Essential for API security
  3. Account lockout: Prevents brute force attacks
  4. Input validation: Never trust user input
  5. Security headers: Add defense in depth
  6. IP blocking: Block known attackers

🎯 Key Takeaways

  • Attacks happen—be prepared
  • Monitoring is essential
  • Rate limiting is your first defense
  • Multiple layers of security are better
  • Don't wait for an attack to implement security

The attack failed, but it was a wake-up call. I'm glad I had basic security in place, but I've strengthened it significantly since then.

Comments

Leave a Comment

Related Posts