fin1te/safecurl

用于替换 'curl_exec' 的直接替换方案,旨在防止 SSRF 攻击。

v1.1 2014-05-20 12:10 UTC

This package is not auto-updated.

Last update: 2024-09-24 06:27:41 UTC


README

SafeCurl旨在作为PHP中curl_exec函数的直接替换方案。SafeCurl会验证URL的每一部分与白名单或黑名单,以帮助防止服务器端请求伪造攻击。

有关项目的更多信息,请参阅博客文章'SafeCurl: SSRF Protection, and a "Capture the Bitcoins"'

保护措施

将URL的每一部分拆分并进行白名单或黑名单验证。这包括将域名解析为其IP地址。

如果您选择启用"FOLLOWLOCATION",则任何重定向都将被捕获并重新验证。

安装

SafeCurl可以通过Composer包含在任何PHP项目中。在composer.json文件下的require中包含以下内容。

    "require": {
        "fin1te\safecurl": "~1"
    }

然后更新Composer。

composer update

使用方法

只需将curl_exec替换为SafeCurl::execute,并用try {} catch {}块包裹即可。

use fin1te\SafeCurl\SafeCurl;
use fin1te\SafeCurl\Exception;

try {
    $url = 'http://www.google.com';

    $curlHandle = curl_init();
    //Your usual cURL options
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (SafeCurl)');

    //Execute using SafeCurl
    $response = SafeCurl::execute($url, $curlHandle);
} catch (Exception $e) {
    //URL wasn't safe
}

选项

默认选项是不允许访问任何私有IP地址,并且仅允许HTTP(S)连接。

如果您想添加自己的选项(例如,将任何请求到您控制的域名的请求列入黑名单),只需创建一个新的SimpleCurl\Options对象,将其添加到白名单或黑名单中,并将其与方法调用一起传递。

域名使用正则表达式语法表示,而IP、协议和端口使用标准字符串(IP可以使用CIDR表示法指定)。

use fin1te\SafeCurl\Options;

$options = new Options();
$options->addToList('blacklist', 'domain', '(.*)\.fin1te\.net');
$options->addToList('whitelist', 'scheme', 'ftp');

//This will now throw an InvalidDomainException
$response = SafeCurl::execute('http://safecurl.fin1te.net', $curlHandle, $options);

//Whilst this will be allowed, and return the response
$response = SafeCurl::execute('ftp://fin1te.net', $curlHandle, $options);

由于我们无法访问已设置的任何cURL选项(请参阅注意事项部分),要启用CURL_FOLLOWREDIRECTS,必须调用enableFollowRedirects()方法。如果您想指定重定向限制,需要调用setMaxRedirects()。传递0将允许无限重定向。

$options = new Options();
$options->enableFollowLocation();
//Abort after 10 redirects
$options->setFollowLocationLimit(10);

URL检查

URL检查方法是公开的,这意味着您可以在应用程序的其他地方使用之前验证URL,尽管您可能想要尝试并捕获任何重定向。

use fin1te\SafeCurl\Url;

try {
    $url = 'http://www.google.com';

    $validatedUrl = Url::validateUrl($url);
    $fullUrl = $validatedUrl['url'];
} catch (Exception $e) {
    // URL wasn't safe
}

可选保护措施

除了标准检查外,还有两个可供选择。

第一个是防止DNS Rebinding攻击。这可以通过在Options对象上调用enablePinDns方法来实现。这个问题的一个主要问题是——SSL证书无法被验证。这是由于在Host头中发送了真实的主机名,并且URL使用了IP地址。

$options = new Options();
$options->enablePinDns();

第二个是禁用URL中的凭据使用,因为PHP的parse_url返回的值与cURL使用的值不同。这是一个临时解决方案。

$options = new Options();
$options->disableSendCredentials();

//This will throw an InvalidURLException
$response = SafeCurl::execute('http://user:pass@google.com', $curlHandle, $options);

注意事项

由于SafeCurl使用getaddrbyhostl来解析域名,它不兼容IPv6,因此该类目前只能与IPv4一起工作。请参阅问题#1

如上所述,我们无法获取对提供的cURL句柄设置的任何cURL选项的值。因为SafeCurl会自己处理重定向,它会关闭CURLOPT_FOLLOWLOCATION并使用Options对象中的值。这也适用于CURLOPT_MAXREDIRECTS

示例

您可以在http://safecurl.fin1te.net/#demo找到现场示例。如果您对站点源代码感兴趣,它托管在fin1te/safecurl.fin1te.net

悬赏

为了帮助使SafeCurl安全并准备好投入生产使用,已经设置了一个比特币悬赏

在文档根目录中有一个比特币钱包,它只能通过127.0.0.1访问。如果您能够绕过保护并获取文件,您可以自由地拿走比特币。