fix(security) : harden auth, session, document access and health endpoint
- Remove orphaned PUBLIC_ACCESS rule for deleted /api/test route - Remove JWT login firewall (app is session-based only) - Set APP_SECRET placeholder (real value must be in .env.local) - Remove JWT env vars from .env - Add session regeneration on login (prevent session fixation) - Remove Document.path from API serialization groups (prevent path leak) - Restrict health check details to ROLE_ADMIN (anonymes get status only) - Add path traversal guard in DocumentStorageService - Convert CreateProfileCommand password to interactive hidden prompt - Restrict Profile Get endpoint to ROLE_ADMIN - Change api firewall to stateless: false (matches session-based auth) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,14 +17,7 @@ class HealthCheckController extends AbstractController
|
||||
#[Route('/api/health', name: 'api_health', methods: ['GET'])]
|
||||
public function __invoke(Connection $connection): JsonResponse
|
||||
{
|
||||
$version = '0.0.0';
|
||||
$versionFile = $this->getParameter('kernel.project_dir').'/VERSION';
|
||||
if (file_exists($versionFile)) {
|
||||
$version = trim(file_get_contents($versionFile));
|
||||
}
|
||||
|
||||
$dbOk = false;
|
||||
$dbLatency = null;
|
||||
$dbOk = false;
|
||||
|
||||
try {
|
||||
$start = hrtime(true);
|
||||
@@ -32,22 +25,33 @@ class HealthCheckController extends AbstractController
|
||||
$dbLatency = round((hrtime(true) - $start) / 1e6, 1);
|
||||
$dbOk = true;
|
||||
} catch (Throwable) {
|
||||
$dbLatency = null;
|
||||
}
|
||||
|
||||
$healthy = $dbOk;
|
||||
$data = ['status' => $healthy ? 'ok' : 'degraded'];
|
||||
|
||||
return $this->json([
|
||||
'status' => $healthy ? 'ok' : 'degraded',
|
||||
'version' => $version,
|
||||
'timestamp' => new DateTimeImmutable()->format(DateTimeInterface::ATOM),
|
||||
'php' => PHP_VERSION,
|
||||
'checks' => [
|
||||
'database' => [
|
||||
'status' => $dbOk ? 'ok' : 'down',
|
||||
'latency_ms' => $dbLatency,
|
||||
if ($this->isGranted('ROLE_ADMIN')) {
|
||||
$version = '0.0.0';
|
||||
$versionFile = $this->getParameter('kernel.project_dir').'/VERSION';
|
||||
if (file_exists($versionFile)) {
|
||||
$version = trim(file_get_contents($versionFile));
|
||||
}
|
||||
|
||||
$data += [
|
||||
'version' => $version,
|
||||
'timestamp' => new DateTimeImmutable()->format(DateTimeInterface::ATOM),
|
||||
'php' => PHP_VERSION,
|
||||
'checks' => [
|
||||
'database' => [
|
||||
'status' => $dbOk ? 'ok' : 'down',
|
||||
'latency_ms' => $dbLatency,
|
||||
],
|
||||
],
|
||||
],
|
||||
'memory_mb' => round(memory_get_usage(true) / 1024 / 1024, 1),
|
||||
], $healthy ? 200 : 503);
|
||||
'memory_mb' => round(memory_get_usage(true) / 1024 / 1024, 1),
|
||||
];
|
||||
}
|
||||
|
||||
return $this->json($data, $healthy ? 200 : 503);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ final class SessionProfileController
|
||||
return new JsonResponse(['message' => 'Mot de passe incorrect.'], JsonResponse::HTTP_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
$session->migrate(true);
|
||||
$session->set('profileId', $profile->getId());
|
||||
$session->set('profileRoles', $profile->getRoles());
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class TestController extends AbstractController
|
||||
{
|
||||
#[Route('/api/test', name: 'api_test', methods: ['GET', 'POST'])]
|
||||
public function test(): JsonResponse
|
||||
{
|
||||
return $this->json(['status' => 'ok', 'message' => 'Test endpoint works!']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user