j0k3r/httplug-ssrf-plugin

GitHub: j0k3r/httplug-ssrf-plugin

专为 PHP HTTPlug 库设计的 SSRF 防护插件,通过解析域名真实 IP 并结合黑白名单机制,有效阻断针对内网资源的非法请求。

Stars: 4 | Forks: 5

# HTTPlug 的服务端请求伪造 (SSRF) 防护插件 ![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/03/63b00a0a29165812.svg) [![Coverage Status](https://coveralls.io/repos/j0k3r/httplug-ssrf-plugin/badge.svg?branch=master&service=github)](https://coveralls.io/github/j0k3r/httplug-ssrf-plugin?branch=master) 受 [SafeCurl](https://github.com/j0k3r/safecurl) 启发,旨在根据白名单或黑名单验证 URL 的每个部分,以帮助在使用 [HTTPlug](https://docs.php-http.org/en/latest/) 时防范_服务端请求伪造_攻击。 URL 的每个部分都会被拆解并根据白名单或黑名单进行验证。这包括将域名解析为其 IP 地址。 ## 安装 可以使用 [Composer](https://getcomposer.org) 将其包含在任何 PHP 项目中。 ``` composer require j0k3r/httplug-ssrf-plugin ``` ## 使用 ``` use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\ServerSideRequestForgeryProtectionPlugin; use Http\Client\Common\PluginClient; use Http\Discovery\Psr18ClientDiscovery; $ssrfPlugin = new ServerSideRequestForgeryProtectionPlugin(); $pluginClient = new PluginClient( Psr18ClientDiscovery::find(), [$ssrfPlugin] ); ``` 如果 URL 无效,该插件会抛出 `Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException` 异常。 #### 选项 默认选项是禁止访问任何[私有 IP 地址](https://en.wikipedia.org/wiki/Private_network),并且仅允许 HTTP(S) 连接。 如果您希望添加自己的选项(例如将向您控制的域名发出的任何请求列入黑名单),只需获取一个新的 `Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Options` 对象,将其添加到白名单或黑名单中,并在方法调用时传递它。 域名使用正则表达式语法表示,而 IP、协议(scheme)和端口则是标准字符串(IP 可以使用 [CIDR 表示法](https://en.wikipedia.org/wiki/Cidr)指定)。 ``` use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Options; use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\ServerSideRequestForgeryProtectionPlugin; use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\Psr18ClientDiscovery; use Http\Client\Common\PluginClient; $options = new Options(); $options->addToList(Options::LIST_BLACKLIST, Options::TYPE_DOMAIN, '(.*)\.example\.com'); $pluginClient = new PluginClient( Psr18ClientDiscovery::find(), [new ServerSideRequestForgeryProtectionPlugin($options)] ); // This will throw an Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException\InvalidDomainException $request = Psr17FactoryDiscovery::findRequestFactory()->createRequest('GET', 'https://www.example.com'); $response = $pluginClient->sendRequest($request); $options = new Options(); $options->setList(Options::LIST_WHITELIST, [Options::TYPE_SCHEME => ['https']]); $pluginClient = new PluginClient( Psr18ClientDiscovery::find(), [new ServerSideRequestForgeryProtectionPlugin($options)] ); // This will be allowed, and return the response $request = Psr17FactoryDiscovery::findRequestFactory()->createRequest('GET', 'https://www.example.com'); $response = $pluginClient->sendRequest($request); // This will throw an Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException\InvalidDomainException $request = Psr17FactoryDiscovery::findRequestFactory()->createRequest('GET', 'https://www.example.com'); $response = $pluginClient->sendRequest($request); ``` #### 可选防护 除了标准检查外,还有两个可用的额外防护。 首先是防止 [DNS Rebinding](https://en.wikipedia.org/wiki/DNS_rebinding) 攻击。这可以通过在 `Options` 对象上调用 `enablePinDns` 方法来启用。但这有一个主要问题 —— SSL 证书**无法**被验证。这是因为真实的主机名是在 `Host` 头中发送的,而 URL 使用的是 IP 地址。 ``` $options = new Options(); $options->enablePinDns(); ``` 其次是禁止在 URL 中使用凭证(credentials),因为 PHP 的 `parse_url` 返回的值与 cURL 使用的值不同。这是一个临时的修复方案。 ``` use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Options; use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\ServerSideRequestForgeryProtectionPlugin; use Http\Discovery\Psr17FactoryDiscovery; use Http\Discovery\Psr18ClientDiscovery; use Http\Client\Common\PluginClient; $options = new Options(); $options->disableSendCredentials(); //This will throw an Http\Client\Exception\RequestException $pluginClient = new PluginClient( Psr18ClientDiscovery::find(), [new ServerSideRequestForgeryProtectionPlugin($options)] ); $request = Psr17FactoryDiscovery::findRequestFactory()->createRequest('GET', 'https://user:pass@google.com'); $response = $pluginClient->sendRequest($request); ``` #### 注意事项 由于该库使用 [`gethostbynamel`](https://php.net/manual/en/function.gethostbynamel.php) 来解析域名,而该函数不兼容 IPv6,因此该类目前仅适用于 IPv4。
标签:API密钥检测, Composer包, ffuf, HTTPlug, IP 地址批量处理, OpenVAS, PHP, SSRF防护, TypeScript, URL过滤, Web安全, 安全插件, 服务端请求伪造, 漏洞缓解, 白名单, 私有化部署, 私有网络保护, 网络安全, 蓝队分析, 输入验证, 防御规避, 隐私保护, 黑名单