Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit559036a

Browse files
committed
Add SameSite cookies to FrameWorkBundle
Uses `session.cookie_samesite` for PHP >= 7.3. For PHP < 7.3 it firstdoes a session_start(), find the emitted header, changes it, and emitsit again with the value for SameSite added.
1 parent441322f commit559036a

File tree

8 files changed

+95
-26
lines changed

8 files changed

+95
-26
lines changed

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
useSymfony\Component\Config\Definition\Builder\TreeBuilder;
2020
useSymfony\Component\Config\Definition\ConfigurationInterface;
2121
useSymfony\Component\Form\Form;
22+
useSymfony\Component\HttpFoundation\Cookie;
2223
useSymfony\Component\Lock\Lock;
2324
useSymfony\Component\Lock\Store\SemaphoreStore;
2425
useSymfony\Component\Messenger\MessageBusInterface;
@@ -482,6 +483,7 @@ private function addSessionSection(ArrayNodeDefinition $rootNode)
482483
->scalarNode('cookie_domain')->end()
483484
->booleanNode('cookie_secure')->end()
484485
->booleanNode('cookie_httponly')->defaultTrue()->end()
486+
->enumNode('cookie_samesite')->values(array(null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT))->defaultNull()->end()
485487
->booleanNode('use_cookies')->end()
486488
->scalarNode('gc_divisor')->end()
487489
->scalarNode('gc_probability')->defaultValue(1)->end()

‎src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c
736736
// session storage
737737
$container->setAlias('session.storage',$config['storage_id'])->setPrivate(true);
738738
$options =array('cache_limiter' =>'0');
739-
foreach (array('name','cookie_lifetime','cookie_path','cookie_domain','cookie_secure','cookie_httponly','use_cookies','gc_maxlifetime','gc_probability','gc_divisor')as$key) {
739+
foreach (array('name','cookie_lifetime','cookie_path','cookie_domain','cookie_secure','cookie_httponly','cookie_samesite','use_cookies','gc_maxlifetime','gc_probability','gc_divisor')as$key) {
740740
if (isset($config[$key])) {
741741
$options[$key] =$config[$key];
742742
}

‎src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ protected static function getBundleDefaultConfig()
231231
'storage_id' =>'session.storage.native',
232232
'handler_id' =>'session.handler.native_file',
233233
'cookie_httponly' =>true,
234+
'cookie_samesite' =>null,
234235
'gc_probability' =>1,
235236
'save_path' =>'%kernel.cache_dir%/sessions',
236237
'metadata_update_threshold' =>'0',

‎src/Symfony/Component/HttpFoundation/HeaderUtils.php‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,42 @@ public static function unquote(string $s): string
143143
returnpreg_replace('/\\\\(.)|"/','$1',$s);
144144
}
145145

146+
/**
147+
* Find the session header amongst the headers that are to be sent, remove it, and return
148+
* it so the caller can process it further.
149+
*/
150+
publicstaticfunctionpopSessionCookie(string$sessionName,string$sessionId): ?string
151+
{
152+
$sessionCookie =null;
153+
$sessionCookiePrefix =sprintf(' %s=',urlencode($sessionName));
154+
$sessionCookieWithId =sprintf('%s%s;',$sessionCookiePrefix,urlencode($sessionId));
155+
$otherCookies =array();
156+
foreach (headers_list()as$h) {
157+
if (0 !==stripos($h,'Set-Cookie:')) {
158+
continue;
159+
}
160+
if (11 ===strpos($h,$sessionCookiePrefix,11)) {
161+
$sessionCookie =$h;
162+
163+
if (11 !==strpos($h,$sessionCookieWithId,11)) {
164+
$otherCookies[] =$h;
165+
}
166+
}else {
167+
$otherCookies[] =$h;
168+
}
169+
}
170+
if (null ===$sessionCookie) {
171+
returnnull;
172+
}
173+
174+
header_remove('Set-Cookie');
175+
foreach ($otherCookiesas$h) {
176+
header($h,false);
177+
}
178+
179+
return$sessionCookie;
180+
}
181+
146182
privatestaticfunctiongroupParts(array$matches,string$separators):array
147183
{
148184
$separator =$separators[0];

‎src/Symfony/Component/HttpFoundation/Session/Storage/Handler/AbstractSessionHandler.php‎

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespaceSymfony\Component\HttpFoundation\Session\Storage\Handler;
1313

14+
useSymfony\Component\HttpFoundation\HeaderUtils;
15+
1416
/**
1517
* This abstract session handler provides a generic implementation
1618
* of the PHP 7.0 SessionUpdateTimestampHandlerInterface,
@@ -121,30 +123,8 @@ public function destroy($sessionId)
121123
if (!$this->sessionName) {
122124
thrownew \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.',\get_class($this)));
123125
}
124-
$sessionCookie =sprintf(' %s=',urlencode($this->sessionName));
125-
$sessionCookieWithId =sprintf('%s%s;',$sessionCookie,urlencode($sessionId));
126-
$sessionCookieFound =false;
127-
$otherCookies =array();
128-
foreach (headers_list()as$h) {
129-
if (0 !==stripos($h,'Set-Cookie:')) {
130-
continue;
131-
}
132-
if (11 ===strpos($h,$sessionCookie,11)) {
133-
$sessionCookieFound =true;
134-
135-
if (11 !==strpos($h,$sessionCookieWithId,11)) {
136-
$otherCookies[] =$h;
137-
}
138-
}else {
139-
$otherCookies[] =$h;
140-
}
141-
}
142-
if ($sessionCookieFound) {
143-
header_remove('Set-Cookie');
144-
foreach ($otherCookiesas$h) {
145-
header($h,false);
146-
}
147-
}else {
126+
$cookie = HeaderUtils::popSessionCookie($this->sessionName,$sessionId);
127+
if (null ===$cookie) {
148128
setcookie($this->sessionName,'',0,ini_get('session.cookie_path'),ini_get('session.cookie_domain'),ini_get('session.cookie_secure'),ini_get('session.cookie_httponly'));
149129
}
150130
}

‎src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespaceSymfony\Component\HttpFoundation\Session\Storage;
1313

14+
useSymfony\Component\HttpFoundation\Cookie;
15+
useSymfony\Component\HttpFoundation\HeaderUtils;
1416
useSymfony\Component\HttpFoundation\Session\SessionBagInterface;
1517
useSymfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler;
1618
useSymfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy;
@@ -48,6 +50,11 @@ class NativeSessionStorage implements SessionStorageInterface
4850
*/
4951
protected$metadataBag;
5052

53+
/**
54+
* @var string|null
55+
*/
56+
private$emulateSameSite;
57+
5158
/**
5259
* Depending on how you want the storage driver to behave you probably
5360
* want to override this constructor entirely.
@@ -67,6 +74,7 @@ class NativeSessionStorage implements SessionStorageInterface
6774
* cookie_lifetime, "0"
6875
* cookie_path, "/"
6976
* cookie_secure, ""
77+
* cookie_samesite, null
7078
* gc_divisor, "100"
7179
* gc_maxlifetime, "1440"
7280
* gc_probability, "1"
@@ -143,6 +151,13 @@ public function start()
143151
thrownew \RuntimeException('Failed to start the session');
144152
}
145153

154+
if (null !==$this->emulateSameSite) {
155+
$originalCookie = HeaderUtils::popSessionCookie(session_name(),session_id());
156+
if (null !==$originalCookie) {
157+
header(sprintf('%s; SameSite=%s',$originalCookie,$this->emulateSameSite));
158+
}
159+
}
160+
146161
$this->loadSession();
147162

148163
returntrue;
@@ -347,7 +362,7 @@ public function setOptions(array $options)
347362

348363
$validOptions =array_flip(array(
349364
'cache_expire','cache_limiter','cookie_domain','cookie_httponly',
350-
'cookie_lifetime','cookie_path','cookie_secure',
365+
'cookie_lifetime','cookie_path','cookie_secure','cookie_samesite',
351366
'gc_divisor','gc_maxlifetime','gc_probability',
352367
'lazy_write','name','referer_check',
353368
'serialize_handler','use_strict_mode','use_cookies',
@@ -359,6 +374,12 @@ public function setOptions(array $options)
359374

360375
foreach ($optionsas$key =>$value) {
361376
if (isset($validOptions[$key])) {
377+
if ('cookie_samesite' ===$key && \PHP_VERSION_ID <703000) {
378+
// PHP <= 7.3 does not support same_site cookies. We will emulate it in
379+
// the start() method instead.
380+
$this->emulateSameSite =$value;
381+
continue;
382+
}
362383
ini_set('url_rewriter.tags' !==$key ?'session.'.$key :$key,$value);
363384
}
364385
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
open
2+
validateId
3+
read
4+
doRead:
5+
read
6+
7+
write
8+
doWrite: foo|s:3:"bar";
9+
close
10+
Array
11+
(
12+
[0] => Content-Type: text/plain; charset=utf-8
13+
[1] => Cache-Control: max-age=0, private, must-revalidate
14+
[2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax
15+
)
16+
shutdown
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
require__DIR__.'/common.inc';
4+
5+
useSymfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
6+
7+
$storage =newNativeSessionStorage(array('cookie_samesite' =>'lax'));
8+
$storage->setSaveHandler(newTestSessionHandler());
9+
$storage->start();
10+
11+
$_SESSION =array('foo' =>'bar');
12+
13+
ob_start(function ($buffer) {returnstr_replace(session_id(),'random_session_id',$buffer); });

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp