j0k3r/httplug-ssrf-plugin
HTTPlug plugin to mitigate SSRF by validating URL parts against configurable allow/deny lists. Resolves hostnames to IPs, blocks private networks by default, and restricts schemes to HTTP/HTTPS. Throws InvalidURLException on invalid targets.
Installation
composer require j0k3r/httplug-ssrf-plugin
Add the plugin to your HTTPlug client stack:
use Http\Client\Common\PluginClient;
use Http\Client\Common\Plugin;
use J0k3r\HttplugSsrfPlugin\SsrfPlugin;
$client = new PluginClient($baseClient);
$client->addPlugin(new SsrfPlugin());
First Use Case
Configure allowed domains in config/ssrf.php (if using Laravel):
'allowed_domains' => [
'api.example.com',
'internal.example.net',
],
Then use the client as usual—invalid requests will throw J0k3r\HttplugSsrfPlugin\Exception\SsrfException.
Centralized Client Setup
Create a reusable client factory in Laravel’s AppServiceProvider:
public function register()
{
$this->app->singleton('ssrfClient', function () {
$client = new PluginClient(new \Http\Adapter\Guzzle7\Client());
$client->addPlugin(new SsrfPlugin(config('ssrf.allowed_domains')));
return $client;
});
}
Dynamic Domain Whitelisting Extend the plugin for runtime updates (e.g., via middleware):
$plugin = new SsrfPlugin(['api.example.com']);
$plugin->setAllowedDomains(['api.example.com', request('dynamic_domain')]);
Fallback for Untrusted Requests Use a secondary client for untrusted requests:
if ($isTrusted) {
return $ssrfClient->sendRequest($request);
}
return $fallbackClient->sendRequest($request);
False Positives
*.example.com vs internal.example.com).$plugin = new SsrfPlugin(['#^api\..+\.example\.com$#']);
Case Sensitivity
'allowed_domains' => array_map('strtolower', ['API.EXAMPLE.COM']),
IPv6 Addresses
::1 or IPv6 literals by default. Extend the validator:
$plugin->setIpValidator(function ($ip) {
return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
});
Log Rejected Requests Override the exception handler to log blocked URIs:
$plugin->setExceptionHandler(function ($request, $exception) {
\Log::warning("SSRF blocked: {$request->getUri()}");
throw $exception;
});
Test Edge Cases Verify with:
$this->expectException(SsrfException::class);
$client->sendRequest(new \Http\Message\Request('GET', 'http://169.254.169.254'));
Custom Validators Add logic for internal IPs or private ranges:
$plugin->addValidator(function ($uri) {
return str_starts_with($uri, 'http://10.');
});
Performance Cache allowed domains if they rarely change:
$plugin = new SsrfPlugin(cache()->remember('ssrf_allowed_domains', 3600, function () {
return config('ssrf.allowed_domains');
}));
Adapter-Specific Quirks
allow_redirects if redirects bypass SSRF checks.withOptions(['max_redirects' => 0]) for stricter control.How can I help you explore Laravel packages today?