Skip to content

Commit c8e3636

Browse files
xh3n1oliverklee
authored andcommitted
[FEATURE] Add security headers to the default response (#110)
1 parent d768aa6 commit c8e3636

File tree

4 files changed

+118
-1
lines changed

4 files changed

+118
-1
lines changed

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@
128128
"messages": {
129129
"Symfony\\Component\\HttpKernel\\Exception\\BadRequestHttpException": true
130130
}
131-
131+
},
132+
"service": {
133+
"view_handler": "my.secure_view_handler"
132134
}
133135
}
134136
}

config/services.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,11 @@ services:
44
public: true
55
autowire: true
66
tags: ['controller.service_arguments']
7+
8+
my.secure_handler:
9+
class: \PhpList\RestBundle\ViewHandler\SecuredViewHandler
10+
11+
my.secure_view_handler:
12+
parent: fos_rest.view_handler.default
13+
calls:
14+
- ['registerHandler', [ 'json', ['@my.secure_handler', 'createResponse'] ] ]
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace PhpList\RestBundle\ViewHandler;
5+
6+
use FOS\RestBundle\View\View;
7+
use FOS\RestBundle\View\ViewHandler;
8+
use Symfony\Component\HttpFoundation\Request;
9+
use Symfony\Component\HttpFoundation\Response;
10+
11+
/**
12+
* This class is used to add headers to the default response.
13+
*
14+
* @author Xheni Myrtaj <xheni@phplist.com>
15+
*/
16+
class SecuredViewHandler
17+
{
18+
/**
19+
* @param ViewHandler $viewHandler
20+
* @param View $view
21+
* @param Request $request
22+
* @param string $format
23+
*
24+
* @return Response
25+
*/
26+
public function createResponse(ViewHandler $handler, View $view, Request $request, string $format): Response
27+
{
28+
$view->setHeaders(
29+
[
30+
'X-Content-Type-Options' => 'nosniff',
31+
'Content-Security-Policy' => "default-src 'none'",
32+
'X-Frame-Options' => 'DENY',
33+
]
34+
);
35+
36+
return $handler->createResponse($view, $request, $format);
37+
}
38+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace PhpList\RestBundle\Tests\System\Controller;
5+
6+
use GuzzleHttp\Client;
7+
use PhpList\Core\TestingSupport\Traits\SymfonyServerTrait;
8+
use PHPUnit\Framework\TestCase;
9+
use Symfony\Component\HttpFoundation\Response;
10+
11+
/**
12+
* Test for security headers
13+
*
14+
* @author Xheni Myrtaj <xheni@phplist.com>
15+
*/
16+
class SecuredViewHandlerTest extends TestCase
17+
{
18+
use SymfonyServerTrait;
19+
20+
/**
21+
* @var Client
22+
*/
23+
private $httpClient = null;
24+
25+
protected function setUp()
26+
{
27+
$this->httpClient = new Client(['http_errors' => false]);
28+
}
29+
30+
protected function tearDown()
31+
{
32+
$this->stopSymfonyServer();
33+
}
34+
35+
/**
36+
* @return string[][]
37+
*/
38+
public function environmentDataProvider(): array
39+
{
40+
return [
41+
'test' => ['test'],
42+
'dev' => ['dev'],
43+
];
44+
}
45+
46+
/**
47+
* @test
48+
* @param string $environment
49+
* @dataProvider environmentDataProvider
50+
*/
51+
public function testSecurityHeaders(string $environment)
52+
{
53+
$this->startSymfonyServer($environment);
54+
55+
$response = $this->httpClient->get(
56+
'/api/v2/sessions',
57+
['base_uri' => $this->getBaseUrl()]
58+
);
59+
$expectedHeaders = [
60+
'X-Content-Type-Options' => 'nosniff',
61+
'Content-Security-Policy' => "default-src 'none'",
62+
'X-Frame-Options' => 'DENY',
63+
];
64+
65+
foreach ($expectedHeaders as $key => $value) {
66+
static::assertSame([$value], $response->getHeader($key));
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)