Overview
SSRF (Server-Side Request Forgery) attacks allow an attacker to induce the server to make unintended requests to internal or external resources. In Laravel apps, this often happens when a user-supplied URL or resource path is fed directly into an HTTP client or PHP stream function. Successful SSRF can lead to data exposure, access to internal services, or interaction with cloud metadata endpoints to steal credentials. Note: no CVEs are referenced in this prompt; this guide is general and focuses on typical Laravel patterns.
Real-world impact includes access to internal networks, scanning ports, or reaching cloud provider metadata endpoints to retrieve credentials or sensitive data. In multi-tenant or API gateway style Laravel applications, an attacker can pivot from an exposed endpoint to talk to internal resources, bypassing firewall rules and causing data leakage or service disruption.
SSRF manifests in Laravel when developers: (a) pass user input directly to Http::get($url) or file_get_contents($url); (b) rely on allow_url_fopen being enabled; (c) follow redirects or do not validate the host, scheme, or DNS. Because Laravel's Http client is a thin wrapper over Guzzle, insecure patterns in host allowlisting translate directly into SSRF risk.
Mitigations involve strict input validation, a host allowlist, limiting redirects, and using a safe wrapper around outbound requests. This guide provides concrete code patterns and steps to reduce surface area and improve visibility.
Code Fix Example
Laravel API Security Remediation
Vulnerable pattern and secure fix in Laravel PHP:
// Vulnerable
<?php
use Illuminate\Http\Request;
class ResourceController {
public function fetch(Request $request) {
$url = $request->input('resource_url');
// Vulnerable: untrusted URL fetched directly
$data = file_get_contents($url);
return response($data);
}
}
// Fixed
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class ResourceController {
public function fetch(Request $request) {
$url = $request->input('resource_url');
// Basic validation
if (!filter_var($url, FILTER_VALIDATE_URL)) {
abort(400, 'Invalid URL');
}
// Enforce allowlisted hosts
$host = parse_url($url, PHP_URL_HOST);
$allowedHosts = ['example.com', 'api.example.com'];
if (!in_array($host, $allowedHosts)) {
abort(403, 'URL not allowed');
}
// Use Http client with strict redirects and timeout
$response = Http::withOptions(['allow_redirects' => false])->timeout(5)->get($url);
if ($response->successful()) {
return response($response->body());
}
abort($response->status());
}
}