Skip to content

Commit 0ac6562

Browse files
committed
HttpExtension: added option sameSiteProtection and Request::isSameSite()
1 parent 387f26b commit 0ac6562

3 files changed

Lines changed: 63 additions & 0 deletions

File tree

src/Bridges/HttpDI/HttpExtension.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class HttpExtension extends Nette\DI\CompilerExtension
2828
'cspReportOnly' => [], // Content-Security-Policy-Report-Only
2929
'featurePolicy' => [], // Feature-Policy
3030
'secureCookie' => 'auto', // true|false|auto Whether the cookie is available only through HTTPS
31+
'sameSiteProtection' => null, // activate Response::isSameSite() protection
3132
];
3233

3334
/** @var bool */
@@ -84,6 +85,15 @@ public function loadConfiguration()
8485
}
8586

8687

88+
public function beforeCompile()
89+
{
90+
if (!empty($this->config['sameSiteProtection'])) {
91+
$this->getContainerBuilder()->getDefinitionByType(Nette\Http\Session::class)
92+
->addSetup('setOptions', [['cookie_samesite' => 'Lax']]);
93+
}
94+
}
95+
96+
8797
public function afterCompile(Nette\PhpGenerator\ClassType $class)
8898
{
8999
if ($this->cliMode) {
@@ -127,6 +137,10 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
127137
$initialize->addBody('$this->getService(?)->setHeader(?, ?);', [$this->prefix('response'), $key, $value]);
128138
}
129139
}
140+
141+
if (!empty($config['sameSiteProtection'])) {
142+
$initialize->addBody('$this->getService(?)->setCookie(...?);', [$this->prefix('response'), ['nette-samesite', '1', 0, null, null, null, true, 'Strict']]);
143+
}
130144
}
131145

132146

src/Http/Request.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ public function isSecured(): bool
227227
}
228228

229229

230+
/**
231+
* Is the request sent from the same origin?
232+
*/
233+
public function isSameSite(): bool
234+
{
235+
return !empty($this->cookies['nette-samesite']);
236+
}
237+
238+
230239
/**
231240
* Is AJAX request?
232241
*/
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\Bridges\HttpDI\HttpExtension;
6+
use Nette\Bridges\HttpDI\SessionExtension;
7+
use Nette\DI;
8+
use Tester\Assert;
9+
10+
11+
require __DIR__ . '/../bootstrap.php';
12+
13+
if (PHP_SAPI === 'cli') {
14+
Tester\Environment::skip('Headers are not testable in CLI mode');
15+
}
16+
17+
18+
$compiler = new DI\Compiler;
19+
$compiler->addExtension('http', new HttpExtension);
20+
$compiler->addExtension('session', new SessionExtension(false, PHP_SAPI === 'cli'));
21+
22+
$loader = new DI\Config\Loader;
23+
$config = $loader->load(Tester\FileMock::create('
24+
http:
25+
sameSiteProtection: yes
26+
', 'neon'));
27+
28+
eval($compiler->addConfig($config)->compile());
29+
30+
$container = new Container;
31+
$container->initialize();
32+
33+
$headers = headers_list();
34+
Assert::contains(
35+
PHP_VERSION_ID >= 70300
36+
? 'Set-Cookie: nette-samesite=1; path=/; HttpOnly; SameSite=Strict'
37+
: 'Set-Cookie: nette-samesite=1; path=/; SameSite=Strict; HttpOnly',
38+
$headers
39+
);
40+
Assert::same('Lax', $container->getService('session.session')->getOptions()['cookie_samesite']);

0 commit comments

Comments
 (0)