-
Notifications
You must be signed in to change notification settings - Fork 510
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix Cookie serialization vulnerability in laravel/framework
- Loading branch information
1 parent
21d8632
commit 8363650
Showing
3 changed files
with
172 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
167 changes: 167 additions & 0 deletions
167
overrides/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
<?php | ||
|
||
namespace Illuminate\Foundation\Http\Middleware; | ||
|
||
use Closure; | ||
use Illuminate\Foundation\Application; | ||
use Illuminate\Support\InteractsWithTime; | ||
use Symfony\Component\HttpFoundation\Cookie; | ||
use Illuminate\Contracts\Encryption\Encrypter; | ||
use Illuminate\Session\TokenMismatchException; | ||
|
||
class VerifyCsrfToken | ||
{ | ||
use InteractsWithTime; | ||
|
||
/** | ||
* The application instance. | ||
* | ||
* @var \Illuminate\Foundation\Application | ||
*/ | ||
protected $app; | ||
|
||
/** | ||
* The encrypter implementation. | ||
* | ||
* @var \Illuminate\Contracts\Encryption\Encrypter | ||
*/ | ||
protected $encrypter; | ||
|
||
/** | ||
* The URIs that should be excluded from CSRF verification. | ||
* | ||
* @var array | ||
*/ | ||
protected $except = []; | ||
|
||
/** | ||
* Create a new middleware instance. | ||
* | ||
* @param \Illuminate\Foundation\Application $app | ||
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter | ||
* @return void | ||
*/ | ||
public function __construct(Application $app, Encrypter $encrypter) | ||
{ | ||
$this->app = $app; | ||
$this->encrypter = $encrypter; | ||
} | ||
|
||
/** | ||
* Handle an incoming request. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @param \Closure $next | ||
* @return mixed | ||
* | ||
* @throws \Illuminate\Session\TokenMismatchException | ||
*/ | ||
public function handle($request, Closure $next) | ||
{ | ||
if ( | ||
$this->isReading($request) || | ||
$this->runningUnitTests() || | ||
$this->inExceptArray($request) || | ||
$this->tokensMatch($request) | ||
) { | ||
return $this->addCookieToResponse($request, $next($request)); | ||
} | ||
|
||
throw new TokenMismatchException; | ||
} | ||
|
||
/** | ||
* Determine if the HTTP request uses a ‘read’ verb. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return bool | ||
*/ | ||
protected function isReading($request) | ||
{ | ||
return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']); | ||
} | ||
|
||
/** | ||
* Determine if the application is running unit tests. | ||
* | ||
* @return bool | ||
*/ | ||
protected function runningUnitTests() | ||
{ | ||
return $this->app->runningInConsole() && $this->app->runningUnitTests(); | ||
} | ||
|
||
/** | ||
* Determine if the request has a URI that should pass through CSRF verification. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return bool | ||
*/ | ||
protected function inExceptArray($request) | ||
{ | ||
foreach ($this->except as $except) { | ||
if ($except !== '/') { | ||
$except = trim($except, '/'); | ||
} | ||
|
||
if ($request->fullUrlIs($except) || $request->is($except)) { | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
/** | ||
* Determine if the session and input CSRF tokens match. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return bool | ||
*/ | ||
protected function tokensMatch($request) | ||
{ | ||
$token = $this->getTokenFromRequest($request); | ||
|
||
return is_string($request->session()->token()) && | ||
is_string($token) && | ||
hash_equals($request->session()->token(), $token); | ||
} | ||
|
||
/** | ||
* Get the CSRF token from the request. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @return string | ||
*/ | ||
protected function getTokenFromRequest($request) | ||
{ | ||
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN'); | ||
|
||
if (! $token && $header = $request->header('X-XSRF-TOKEN')) { | ||
$token = $this->encrypter->decrypt($header, false); | ||
} | ||
|
||
return $token; | ||
} | ||
|
||
/** | ||
* Add the CSRF token to the response cookies. | ||
* | ||
* @param \Illuminate\Http\Request $request | ||
* @param \Symfony\Component\HttpFoundation\Response $response | ||
* @return \Symfony\Component\HttpFoundation\Response | ||
*/ | ||
protected function addCookieToResponse($request, $response) | ||
{ | ||
$config = config('session'); | ||
|
||
$response->headers->setCookie( | ||
new Cookie( | ||
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']), | ||
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null | ||
) | ||
); | ||
|
||
return $response; | ||
} | ||
} |