Skip to content
Permalink
Browse files Browse the repository at this point in the history
added checks for evil URL's (url's that could trigger parse errors an…
…d ssrf attacks)

added test for double port number ssrf attack and prevent it
  • Loading branch information
poef committed Sep 26, 2017
1 parent 615c841 commit 1feb1cc
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 12 deletions.
28 changes: 16 additions & 12 deletions src/url/Url.php
Expand Up @@ -12,36 +12,40 @@
namespace arc\url;

/**
* Url parses a URL string and returns an object with the seperate parts. You can change
* these and when cast to a string Url will regenerate the URL string and make sure it
* is valid.
* Url parses a URL string and returns an object with the seperate parts. You can change
* these and when cast to a string Url will regenerate the URL string and make sure it
* is valid.
*
* Usage:
* $url = new \arc\url\Url( 'http://www.ariadne-cms.org/' );
* $url->path = '/docs/search/';
* $url->query = 'a=1&a=2';
* echo $url; // => 'http://www.ariadne-cms.org/docs/search/?a=1&a=2'
* Usage:
* $url = new \arc\url\Url( 'http://www.ariadne-cms.org/' );
* $url->path = '/docs/search/';
* $url->query = 'a=1&a=2';
* echo $url; // => 'http://www.ariadne-cms.org/docs/search/?a=1&a=2'
* @property Query $query The query arguments
*/
class Url
{
/**
* All parts of the URL format, as returned by parse_url.
* scheme://user:pass@host:port/path?query#fragment
* All parts of the URL format, as returned by parse_url.
* scheme://user:pass@host:port/path?query#fragment
*/
public $scheme, $user, $pass, $host, $port, $path, $fragment;
private $query;

/**
* @param string $url The URL to parse, the query part will remain a string.
* @param QueryInterface queryObject Optional. An object that parses the query string.
* @param string $url The URL to parse, the query part will remain a string.
* @param QueryInterface queryObject Optional. An object that parses the query string.
*/
public function __construct($url, $queryObject = null)
{
$componentList = [
'scheme', 'host', 'port', 'user', 'pass', 'path', 'query', 'fragment'
];
$this->importUrlComponents( parse_url( $url ), $componentList );
if ($this->scheme!='ldap' && strpos($this->host, ':')) {
// parse_url allows ':' in host when it occurs more than once\
$this->host = substr($this->host, 0, strpos($this->host, ':'));
}
if ( isset( $queryObject ) ) {
$this->query = $queryObject->import( $this->query );
}
Expand Down
55 changes: 55 additions & 0 deletions tests/url.Test.php
Expand Up @@ -109,4 +109,59 @@ function testParseCommonURLS()
$this->assertEquals( $commonUrls, $parsedUrls);
}

function testEvilURL1()
{
$evilURL = 'http://127.0.0.1:11211:80/';
$parsed = \arc\url::url($evilURL);
$this->assertEquals( $parsed->port, 80 );
$parsedSafe = \arc\url::safeUrl($evilURL);
$this->assertEquals( $parsedSafe->port, 80 );
$safeURL = (string) $parsed;
$this->assertEquals( 'http://127.0.0.1:80/', $safeURL);
}

function testEvilURL2()
{
$evilURL = 'http://google.com#@evil.com/';
$parsed = \arc\url::url($evilURL);
$this->assertEquals( $parsed->host, 'google.com' );
$parsedSafe = \arc\url::safeUrl($evilURL);
$this->assertEquals( $parsedSafe->host, 'google.com');
$safeURL = (string) $parsed;
$this->assertEquals( 'http://google.com#%40evil.com%2F', $safeURL);
}

function testEvilURL3()
{
$evilURL = 'http://foo@evil.com:80@google.com/';
$parsed = \arc\url::url($evilURL);
$this->assertEquals( $parsed->host, 'google.com' );
$parsedSafe = \arc\url::safeUrl($evilURL);
$this->assertEquals( $parsedSafe->host, 'google.com');
$safeURL = (string) $parsed;
$this->assertEquals( 'http://foo%40evil.com:80@google.com/', $safeURL);
}

function testEvilURL4()
{
$evilURL = 'http://foo@127.0.0.1 @google.com/';
$parsed = \arc\url::url($evilURL);
$this->assertEquals( $parsed->host, 'google.com' );
$parsedSafe = \arc\url::safeUrl($evilURL);
$this->assertEquals( $parsedSafe->host, 'google.com');
$safeURL = (string) $parsed;
$this->assertEquals( 'http://foo%40127.0.0.1%20@google.com/', $safeURL);
}

function testEvilURL5()
{
$evilURL = 'http://127.0.0.1:11211#@google.com:80/';
$parsed = \arc\url::url($evilURL);
$this->assertEquals( $parsed->host, '127.0.0.1' );
$parsedSafe = \arc\url::safeUrl($evilURL);
$this->assertEquals( $parsedSafe->host, '127.0.0.1');
$safeURL = (string) $parsed;
$this->assertEquals( 'http://127.0.0.1:11211#%40google.com%3A80%2F', $safeURL);
}

}

0 comments on commit 1feb1cc

Please sign in to comment.