Clickjacking in Laravel
How Clickjacking Manifests in Laravel
Clickjacking in Laravel applications typically occurs when developers fail to implement proper frame-busting mechanisms or rely on outdated security headers. Laravel's default configurations don't automatically protect against clickjacking, making this a common vulnerability in Laravel applications.
The most prevalent attack pattern involves embedding a Laravel application within an iframe on a malicious site. Attackers create seemingly innocuous pages that load the target Laravel application in a hidden iframe, then overlay deceptive UI elements that trick users into clicking buttons or links they can't see. For example, an attacker might create a game where users think they're clicking on a button to earn points, but they're actually interacting with a Laravel admin panel's 'Delete User' button.
Laravel applications are particularly vulnerable when they handle sensitive operations like:
- Admin panel functions (user management, content moderation)
- Financial transactions (payment processing, fund transfers)
- Account modifications (password changes, email updates)
- System configuration changes
Common Laravel-specific scenarios include:
// Vulnerable: No frame protection
Route::post('/admin/delete-user', [AdminController::class, 'deleteUser']);
Route::post('/transfer-funds', [PaymentController::class, 'transfer']);
Route::post('/update-profile', [ProfileController::class, 'update']);Even when using Laravel's CSRF protection, clickjacking can bypass these defenses because the malicious site can still submit the hidden form. The attack succeeds because users believe they're interacting with the attacker's page, not your Laravel application.
Laravel-Specific Detection
Detecting clickjacking in Laravel applications requires examining both the application code and HTTP response headers. Start by checking your Laravel application's HTTP responses for the X-Frame-Options header and Content-Security-Policy frame-ancestors directive.
// Check headers using curl
curl -I https://your-laravel-app.com
// Look for:
// X-Frame-Options: DENY or SAMEORIGIN
// Content-Security-Policy: frame-ancestors 'none' or 'self'In Laravel, you can inspect middleware to see if frame protection is implemented. Open app/Http/Middleware and look for any clickjacking protection middleware. Laravel doesn't include this by default, so you'll need to create it or use a package.
middleBrick's Laravel-specific scanning identifies clickjacking vulnerabilities by:
- Checking for missing X-Frame-Options headers across all endpoints
- Verifying Content-Security-Policy frame-ancestors directives
- Testing if sensitive endpoints can be loaded in iframes
- Analyzing route definitions for operations that shouldn't be frame-accessible
- Checking for inline JavaScript that might interfere with frame-busting
The scanner runs in under 15 seconds and provides specific findings like:
Clickjacking Vulnerability Detected
Severity: High
Endpoint: POST /admin/delete-user
Issue: Missing X-Frame-Options header
Recommendation: Add frame protection middlewareFor Laravel applications using packages like Laravel Fortify or Jetstream, ensure these packages' authentication routes aren't vulnerable to clickjacking, as they often handle sensitive operations like password resets and account modifications.
Laravel-Specific Remediation
Remediating clickjacking in Laravel applications involves multiple layers of protection. The most effective approach combines HTTP headers with Laravel middleware.
First, create a clickjacking protection middleware:
// app/Http/Middleware/FrameGuard.php
headers->set('X-Frame-Options', $guard === 'sameorigin' ? 'SAMEORIGIN' : 'DENY');
// Set Content-Security-Policy header
$csp = $guard === 'sameorigin'
? "frame-ancestors 'self'"
: "frame-ancestors 'none'";
$response->headers->set('Content-Security-Policy', $csp);
return $response;
}
}Register the middleware in app/Http/Kernel.php:
// Add to $middleware array for global protection
protected $middleware = [
// ... existing middleware
\App\Http\Middleware\FrameGuard::class,
];For selective protection, add it to $routeMiddleware and apply it to specific routes:
// app/Http/Kernel.php
protected $routeMiddleware = [
// ... existing middleware
'frame-guard' => \App\Http\Middleware\FrameGuard::class,
];Apply to sensitive routes:
// routes/web.php
Route::post('/admin/delete-user', [AdminController::class, 'deleteUser'])
->middleware('frame-guard:deny');
Route::post('/transfer-funds', [PaymentController::class, 'transfer'])
->middleware('frame-guard:deny');
Route::post('/update-profile', [ProfileController::class, 'update'])
->middleware('frame-guard:deny');For Laravel applications that need to allow framing from specific domains (rare but possible for embedded dashboards), use:
Route::get('/dashboard', [DashboardController::class, 'show'])
->middleware('frame-guard:sameorigin');middleBrick's CLI tool can verify your remediation:
npx middlebrick scan https://your-laravel-app.com/admin/delete-user
// Returns JSON with frame protection status
// Helps ensure your middleware is properly configuredAfter implementing these changes, use middleBrick's continuous monitoring to ensure your clickjacking protections remain effective as your Laravel application evolves.