Show a warning if using the default APP_SECRET value

This commit is contained in:
Jan Böhmer 2026-06-07 22:26:45 +02:00
parent c229208bd5
commit f888e10827
5 changed files with 111 additions and 3 deletions

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/
namespace App\Command;
use App\Services\System\AppSecretChecker;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -33,7 +34,9 @@ use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
#[AsCommand('partdb:check-requirements', 'Checks if the requirements Part-DB needs or recommends are fulfilled.')]
class CheckRequirementsCommand extends Command
{
public function __construct(protected ContainerBagInterface $params)
public function __construct(protected ContainerBagInterface $params, AppSecretChecker $secretChecker,
private readonly AppSecretChecker $appSecretChecker
)
{
parent::__construct();
}
@ -121,6 +124,16 @@ class CheckRequirementsCommand extends Command
$io->success('Debug mode disabled.');
}
//Check if APP_SECRET has been changed from the default
if ($io->isVerbose()) {
$io->comment('Checking APP_SECRET...');
}
if ($this->appSecretChecker->isInsecureSecret()) {
$io->warning('APP_SECRET is set to the default value shipped with Part-DB. This is a security risk! Generate a new secret (e.g. using "openssl rand -hex 32") and set it as APP_SECRET in your .env.local file.');
} elseif (!$only_issues) {
$io->success('APP_SECRET has been changed from the default value.');
}
}
protected function checkPHPExtensions(SymfonyStyle $io, bool $only_issues = false): void

View file

@ -24,6 +24,7 @@ namespace App\Controller;
use App\DataTables\LogDataTable;
use App\Entity\Parts\Part;
use App\Services\System\AppSecretChecker;
use App\Services\System\BannerHelper;
use App\Services\System\GitVersionInfoProvider;
use App\Services\System\UpdateAvailableFacade;
@ -36,8 +37,11 @@ use Symfony\Component\Routing\Attribute\Route;
class HomepageController extends AbstractController
{
public function __construct(private readonly DataTableFactory $dataTable, private readonly BannerHelper $bannerHelper)
{
public function __construct(
private readonly DataTableFactory $dataTable,
private readonly BannerHelper $bannerHelper,
private readonly AppSecretChecker $appSecretChecker,
) {
}
@ -84,6 +88,8 @@ class HomepageController extends AbstractController
'new_version_available' => $updateAvailableManager->isUpdateAvailable(),
'new_version' => $updateAvailableManager->getLatestVersionString(),
'new_version_url' => $updateAvailableManager->getLatestVersionUrl(),
'insecure_app_secret' => $this->appSecretChecker->isInsecureSecret(),
'suggested_app_secret' => $this->appSecretChecker->isInsecureSecret() ? $this->appSecretChecker->generateSecret() : null,
]);
}
}

View file

@ -0,0 +1,62 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2024 Jan Böhmer (https://github.com/jbtronics)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\System;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
/**
* Checks whether APP_SECRET has been changed from the default value shipped with Part-DB.
*/
final readonly class AppSecretChecker
{
/** Known default/example secrets that must not be used in production. */
public const INSECURE_SECRETS = [
'a03498528f5a5fc089273ec9ae5b2849', // default in .env
'318b5d659e07a0b3f96d9b3a83b254ca', // default in .env.dev
];
public function __construct(
#[Autowire('%kernel.secret%')]
private string $appSecret,
) {
}
/**
* @return bool True if the app secret is one of the known insecure default secrets, false otherwise.
*/
public function isInsecureSecret(): bool
{
return in_array($this->appSecret, self::INSECURE_SECRETS, true);
}
/**
* Generates a new random app secret that can be used to replace the default insecure one.
* @return string
* @throws \Random\RandomException
*/
public function generateSecret(): string
{
//Symfony docs recommend 32 characters for the app secret, which are 16 random bytes when hex-encoded.
return bin2hex(random_bytes(16));
}
}