2017 © Pedro Peláez
 

library safecurl

A drop-in replacement for 'curl_exec', designed to prevent SSRF attacks.

image

fin1te/safecurl

A drop-in replacement for 'curl_exec', designed to prevent SSRF attacks.

  • Thursday, May 22, 2014
  • by fin1te
  • Repository
  • 5 Watchers
  • 48 Stars
  • 523 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 7 Forks
  • 13 Open issues
  • 3 Versions
  • 0 % Grown

The README.md

SafeCurl

SafeCurl intends to be a drop-in replacement for the curl_exec function in PHP. SafeCurl validates each part of the URL against a white or black list, to help protect against Server-Side Request Forgery attacks., (*1)

For more infomation about the project see the blog post 'SafeCurl: SSRF Protection, and a "Capture the Bitcoins"'., (*2)

Protections

Each part of the URL is broken down and validated against a white or black list. This includes resolve a domain name to it's IP addresses., (*3)

If you chose to enable "FOLLOWLOCATION", then any redirects are caught, and re-validated., (*4)

Installation

SafeCurl can be included in any PHP project using Composer. Include the following in your composer.json file under require., (*5)

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

Then update Composer., (*6)

composer update

Usage

It's as easy as replacing curl_exec with SafeCurl::execute, and wrapping it in a try {} catch {} block., (*7)

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
}

Options

The default options are to not allow access to any private IP addresses, and to only allow HTTP(S) connections., (*8)

If you wish to add your own options (such as to blacklist any requests to domains your control), simply get a new SimpleCurl\Options object, add to the white or black lists, and pass it along with the method calls., (*9)

Domains are express using regex syntax, whilst IPs, scheme and ports are standard strings (IPs can be specified in CIDR notation)., (*10)

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);

Since we can't get access to any already set cURL options (see Caveats section), to enable CURL_FOLLOWREDIRECTS you must call the enableFollowRedirects() method. If you wish to specify a redirect limit, you will need to call setMaxRedirects(). Passing in 0 will allow infinite redirects., (*11)

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

URL Checking

The URL checking methods are also public, meaning that you can validate a URL before using it elsewhere in your application, although you'd want to try and catch any redirects., (*12)

use fin1te\SafeCurl\Url;

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

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

Optional Protections

In addition to the standard checks, two more are available., (*13)

The first is to prevent DNS Rebinding attacks. This can be enabled by calling the enablePinDns method on an Options object. There is one major issue with this - the SSL certificate can't be validated. This is due to the real hostname being sent in the Host header, and the URL using the IP address., (*14)

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

The second disables the use of credentials in a URL, since PHP's parse_url returns values which differ from ones cURL uses. This is a temporary fix., (*15)

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

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

Cavets

Since SafeCurl uses getaddrbyhostl to resolve domain names, which isn't IPv6 compatible, the class will only work with IPv4 at the moment. See Issue #1., (*16)

As mentioned above, we can't fetch the value of any cURL options set against the provided cURL handle. Because SafeCurl handles redirects itself, it will turn off CURLOPT_FOLLOWLOCATION and use the value from the Options object. This is also true of CURLOPT_MAXREDIRECTS., (*17)

Demo

A live demo is available at http://safecurl.fin1te.net/#demo. For the site source code (if you're curious), it's hosted at fin1te/safecurl.fin1te.net., (*18)

Bounty

In order to help make SafeCurl secure and ready for production use, a Bitcoin bounty has been setup., (*19)

Inside the document root is a Bitcoin wallet, which is only accessible by 127.0.0.1. If you can bypass the protections and grab the file, you're free to take the Bitcoins., (*20)

The Versions

22/05 2014

dev-master

9999999-dev

A drop-in replacement for 'curl_exec', designed to prevent SSRF attacks.

  Sources   Download

MIT

The Requires

  • php >=5.3.0

 

The Development Requires

by Jack W

curl safe safecurl ssrf websec

20/05 2014

v1.1

1.1.0.0

A drop-in replacement for 'curl_exec', designed to prevent SSRF attacks.

  Sources   Download

MIT

The Requires

  • php >=5.3.0

 

The Development Requires

by Jack W

curl safe safecurl ssrf websec

19/05 2014

v1.0

1.0.0.0

A drop-in replacement for 'curl_exec', designed to prevent SSRF attacks.

  Sources   Download

The Requires

  • php >=5.3.0

 

The Development Requires

by Jack W

curl safe safecurl ssrf websec