diff --git a/laravel/cookie.php b/laravel/cookie.php index 1c3b5873..21c67bb7 100644 --- a/laravel/cookie.php +++ b/laravel/cookie.php @@ -44,9 +44,14 @@ class Cookie { */ public static function get($name, $default = null) { - if (isset(static::$jar[$name])) return static::$jar[$name]['value']; + if (isset(static::$jar[$name])) return static::parse(static::$jar[$name]['value']); - return array_get(Request::foundation()->cookies->all(), $name, $default); + if ( ! is_null($value = Request::foundation()->cookies->get($name))) + { + return static::parse($value); + } + + return value($default); } /** @@ -75,6 +80,8 @@ class Cookie { $expiration = time() + ($expiration * 60); } + $value = sha1($value.Config::get('application.key')).'+'.$value; + // If the secure option is set to true, yet the request is not over HTTPS // we'll throw an exception to let the developer know that they are // attempting to send a secure cookie over the insecure HTTP. @@ -120,4 +127,35 @@ class Cookie { return static::put($name, null, -2000, $path, $domain, $secure); } + /** + * Parse a hash fingerprinted cookie value. + * + * @param string $value + * @return string + */ + protected static function parse($value) + { + $segments = explode('+', $value); + + // First we will make sure the cookie actually has enough segments to even + // be valid as being set by the application. If it does not we will go + // ahead and throw exceptions now since there the cookie is invalid. + if ( ! (count($segments) >= 2)) + { + throw new \Exception("Cookie was not set by application."); + } + + $value = implode('+', array_slice($segments, 1)); + + // Now we will check if the SHA-1 hash present in the first segment matches + // the ShA-1 hash of the rest of the cookie value, since the hash should + // have been set when the cookie was first created by the application. + if ($segments[0] == sha1($value.Config::get('application.key'))) + { + return $value; + } + + throw new \Exception("Cookie has been modified by client."); + } + } diff --git a/laravel/tests/cases/auth.test.php b/laravel/tests/cases/auth.test.php index 16ba428a..44ff671e 100644 --- a/laravel/tests/cases/auth.test.php +++ b/laravel/tests/cases/auth.test.php @@ -269,7 +269,7 @@ class AuthTest extends PHPUnit_Framework_TestCase { $this->assertTrue(isset(Cookie::$jar['laravel_auth_drivers_fluent_remember'])); - $cookie = Cookie::$jar['laravel_auth_drivers_fluent_remember']['value']; + $cookie = Cookie::get('laravel_auth_drivers_fluent_remember'); $cookie = explode('|', Crypter::decrypt($cookie)); $this->assertEquals(1, $cookie[0]); $this->assertEquals('foo', Cookie::$jar['laravel_auth_drivers_fluent_remember']['path']); diff --git a/laravel/tests/cases/cookie.test.php b/laravel/tests/cases/cookie.test.php index f62f7857..e17070b0 100644 --- a/laravel/tests/cases/cookie.test.php +++ b/laravel/tests/cases/cookie.test.php @@ -67,7 +67,7 @@ class CookieTest extends \PHPUnit_Framework_TestCase { */ public function testHasMethodIndicatesIfCookieInSet() { - Cookie::$jar['foo'] = array('value' => 'bar'); + Cookie::$jar['foo'] = array('value' => sha1('bar'.Config::get('application.key')).'+bar'); $this->assertTrue(Cookie::has('foo')); $this->assertFalse(Cookie::has('bar')); @@ -82,7 +82,7 @@ class CookieTest extends \PHPUnit_Framework_TestCase { */ public function testGetMethodCanReturnValueOfCookies() { - Cookie::$jar['foo'] = array('value' => 'bar'); + Cookie::$jar['foo'] = array('value' => sha1('bar'.Config::get('application.key')).'+bar'); $this->assertEquals('bar', Cookie::get('foo')); Cookie::put('bar', 'baz'); @@ -97,7 +97,7 @@ class CookieTest extends \PHPUnit_Framework_TestCase { public function testForeverShouldUseATonOfMinutes() { Cookie::forever('foo', 'bar'); - $this->assertEquals('bar', Cookie::$jar['foo']['value']); + $this->assertEquals(sha1('bar'.Config::get('application.key')).'+bar', Cookie::$jar['foo']['value']); // Shouldn't be able to test this cause while we indicate -2000 seconds // cookie expiration store timestamp. diff --git a/laravel/tests/cases/session.test.php b/laravel/tests/cases/session.test.php index cf6946a7..b46b5ba0 100644 --- a/laravel/tests/cases/session.test.php +++ b/laravel/tests/cases/session.test.php @@ -372,7 +372,7 @@ class SessionTest extends PHPUnit_Framework_TestCase { $cookie = Cookie::$jar[Config::get('session.cookie')]; - $this->assertEquals('foo', $cookie['value']); + $this->assertEquals(sha1('foo'.Config::get('application.key')).'+foo', $cookie['value']); // Shouldn't be able to test this cause session.lifetime store number of minutes // while cookie expiration store timestamp when it going to expired. // $this->assertEquals(Config::get('session.lifetime'), $cookie['expiration']);