Skip to content

Commit 8363650

Browse files
Fix Cookie serialization vulnerability in laravel/framework
1 parent 21d8632 commit 8363650

File tree

3 files changed

+172
-3
lines changed

3 files changed

+172
-3
lines changed

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"Codedge\\Updater\\SourceRepositoryTypes\\": "overrides/codedge/laravel-selfupdater/src/SourceRepositoryTypes/",
106106
"Barryvdh\\TranslationManager\\": "overrides/barryvdh/laravel-translation-manager/src/",
107107
"Illuminate\\Foundation\\": "overrides/laravel/framework/src/Illuminate/Foundation/",
108+
"Illuminate\\Foundation\\Http\\Middleware\\": "overrides/laravel/framework/src/Illuminate/Foundation/Http/Middleware/",
108109
"Illuminate\\Routing\\": "overrides/laravel/framework/src/Illuminate/Routing/",
109110
"Illuminate\\Broadcasting\\Broadcasters\\": "overrides/laravel/framework/src/Illuminate/Broadcasting/Broadcasters/",
110111
"Illuminate\\Validation\\Concerns\\": "overrides/laravel/framework/src/Illuminate/Validation/Concerns/",
@@ -188,6 +189,7 @@
188189
"vendor/barryvdh/laravel-translation-manager/src/Controller.php",
189190
"vendor/laravel/framework/src/Illuminate/Foundation/ProviderRepository.php",
190191
"vendor/laravel/framework/src/Illuminate/Foundation/PackageManifest.php",
192+
"vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php",
191193
"vendor/laravel/framework/src/Illuminate/Routing/UrlGenerator.php",
192194
"vendor/laravel/framework/src/Illuminate/Routing/RouteSignatureParameters.php",
193195
"vendor/laravel/framework/src/Illuminate/Routing/RouteDependencyResolverTrait.php",

overrides/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ protected function decryptCookie($cookie)
103103
{
104104
return is_array($cookie)
105105
? $this->decryptArray($cookie)
106-
: $this->encrypter->decrypt($cookie);
106+
: $this->encrypter->decrypt($cookie, false);
107107
}
108108

109109
/**
@@ -118,7 +118,7 @@ protected function decryptArray(array $cookie)
118118

119119
foreach ($cookie as $key => $value) {
120120
if (is_string($value)) {
121-
$decrypted[$key] = $this->encrypter->decrypt($value);
121+
$decrypted[$key] = $this->encrypter->decrypt($value, false);
122122
}
123123
}
124124

@@ -145,7 +145,7 @@ protected function encrypt(Response $response)
145145
}
146146

147147
$response->headers->setCookie($this->duplicate(
148-
$cookie, $this->encrypter->encrypt($prefix.$cookie->getValue())
148+
$cookie, $this->encrypter->encrypt($prefix.$cookie->getValue(), false)
149149
));
150150
}
151151

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
namespace Illuminate\Foundation\Http\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Foundation\Application;
7+
use Illuminate\Support\InteractsWithTime;
8+
use Symfony\Component\HttpFoundation\Cookie;
9+
use Illuminate\Contracts\Encryption\Encrypter;
10+
use Illuminate\Session\TokenMismatchException;
11+
12+
class VerifyCsrfToken
13+
{
14+
use InteractsWithTime;
15+
16+
/**
17+
* The application instance.
18+
*
19+
* @var \Illuminate\Foundation\Application
20+
*/
21+
protected $app;
22+
23+
/**
24+
* The encrypter implementation.
25+
*
26+
* @var \Illuminate\Contracts\Encryption\Encrypter
27+
*/
28+
protected $encrypter;
29+
30+
/**
31+
* The URIs that should be excluded from CSRF verification.
32+
*
33+
* @var array
34+
*/
35+
protected $except = [];
36+
37+
/**
38+
* Create a new middleware instance.
39+
*
40+
* @param \Illuminate\Foundation\Application $app
41+
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
42+
* @return void
43+
*/
44+
public function __construct(Application $app, Encrypter $encrypter)
45+
{
46+
$this->app = $app;
47+
$this->encrypter = $encrypter;
48+
}
49+
50+
/**
51+
* Handle an incoming request.
52+
*
53+
* @param \Illuminate\Http\Request $request
54+
* @param \Closure $next
55+
* @return mixed
56+
*
57+
* @throws \Illuminate\Session\TokenMismatchException
58+
*/
59+
public function handle($request, Closure $next)
60+
{
61+
if (
62+
$this->isReading($request) ||
63+
$this->runningUnitTests() ||
64+
$this->inExceptArray($request) ||
65+
$this->tokensMatch($request)
66+
) {
67+
return $this->addCookieToResponse($request, $next($request));
68+
}
69+
70+
throw new TokenMismatchException;
71+
}
72+
73+
/**
74+
* Determine if the HTTP request uses a ‘read’ verb.
75+
*
76+
* @param \Illuminate\Http\Request $request
77+
* @return bool
78+
*/
79+
protected function isReading($request)
80+
{
81+
return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
82+
}
83+
84+
/**
85+
* Determine if the application is running unit tests.
86+
*
87+
* @return bool
88+
*/
89+
protected function runningUnitTests()
90+
{
91+
return $this->app->runningInConsole() && $this->app->runningUnitTests();
92+
}
93+
94+
/**
95+
* Determine if the request has a URI that should pass through CSRF verification.
96+
*
97+
* @param \Illuminate\Http\Request $request
98+
* @return bool
99+
*/
100+
protected function inExceptArray($request)
101+
{
102+
foreach ($this->except as $except) {
103+
if ($except !== '/') {
104+
$except = trim($except, '/');
105+
}
106+
107+
if ($request->fullUrlIs($except) || $request->is($except)) {
108+
return true;
109+
}
110+
}
111+
112+
return false;
113+
}
114+
115+
/**
116+
* Determine if the session and input CSRF tokens match.
117+
*
118+
* @param \Illuminate\Http\Request $request
119+
* @return bool
120+
*/
121+
protected function tokensMatch($request)
122+
{
123+
$token = $this->getTokenFromRequest($request);
124+
125+
return is_string($request->session()->token()) &&
126+
is_string($token) &&
127+
hash_equals($request->session()->token(), $token);
128+
}
129+
130+
/**
131+
* Get the CSRF token from the request.
132+
*
133+
* @param \Illuminate\Http\Request $request
134+
* @return string
135+
*/
136+
protected function getTokenFromRequest($request)
137+
{
138+
$token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
139+
140+
if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
141+
$token = $this->encrypter->decrypt($header, false);
142+
}
143+
144+
return $token;
145+
}
146+
147+
/**
148+
* Add the CSRF token to the response cookies.
149+
*
150+
* @param \Illuminate\Http\Request $request
151+
* @param \Symfony\Component\HttpFoundation\Response $response
152+
* @return \Symfony\Component\HttpFoundation\Response
153+
*/
154+
protected function addCookieToResponse($request, $response)
155+
{
156+
$config = config('session');
157+
158+
$response->headers->setCookie(
159+
new Cookie(
160+
'XSRF-TOKEN', $request->session()->token(), $this->availableAt(60 * $config['lifetime']),
161+
$config['path'], $config['domain'], $config['secure'], false, false, $config['same_site'] ?? null
162+
)
163+
);
164+
165+
return $response;
166+
}
167+
}

0 commit comments

Comments
 (0)