Forráskód Böngészése

fix: remove unused APP_SECRET / UI_SECRET (SEC_REVIEW F66 + F67)

`APP_SECRET` and `UI_SECRET` were declared in `.env.example` and
read into the api/ui settings array, but never used for any
signing or HMAC operation:

  - No callsite under `api/src/` references `app_secret`.
  - No callsite under `ui/src/` references `ui_secret`.
  - `ConfigController` did mask `APP_SECRET` for display, but the
    underlying value was unused.
  - `.env.example` and `doc/user-manual.md` / `doc/security.md`
    instructed operators to generate `openssl rand -hex 32` for
    both — implying they protected something they didn't.

Picking between the SEC_REVIEW's two suggested fixes (wire them
or remove them), removal is the lower-effort, lower-misleading
option. Inventing a use case to justify keeping the env vars
would add ceremony with no real security benefit; the actual
signing surfaces (CSRF token, session ID, internal-job token,
service token) all already use their own dedicated entropy.

Removed:
  - `.env.example` — `APP_SECRET=…` and `UI_SECRET=…` lines.
  - `api/config/settings.php` — `'app_secret'` settings key.
  - `ui/config/settings.php` — `'ui_secret'` settings key.
  - `api/src/Application/Admin/ConfigController.php` — the
    `APP_SECRET` line in the `app` section's masked output,
    plus the docblock entry in the masking-rules list.
  - `api/src/Infrastructure/Logging/SecretScrubbingProcessor.php`
    — `app_secret` listed in the doc-comment as an example
    sensitive key (the substring `secret` is still in
    `SENSITIVE_KEY_NEEDLES`, so future keys with that
    substring still get scrubbed).
  - `api/tests/Integration/Support/AppTestCase.php` and
    `ui/tests/Integration/Support/AppTestCase.php` — test
    fixture overrides that fed dummy values for the now-
    deleted settings keys.
  - `doc/user-manual.md` — env-var generation table rows.
  - `doc/security.md` — secret-inventory bullet and the
    `APP_SECRET` mention in the masked-config description.

Operators upgrading from a prior release can leave the
`APP_SECRET=…` and `UI_SECRET=…` lines in their `.env`; both
apps now ignore them. F67 (validator-doesn't-check-UI_SECRET) is
resolved by the same change since `UI_SECRET` no longer exists
to validate against.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chiappa 3 napja
szülő
commit
4a764f58f0

+ 0 - 2
.env.example

@@ -20,7 +20,6 @@ UI_SERVICE_TOKEN=
 # -----------------------------------------------------------------------------
 APP_ENV=production           # development | production
 LOG_LEVEL=info
-APP_SECRET=                  # 32-byte hex; used internally for signing things like ETags
 
 # Database
 DB_DRIVER=sqlite             # sqlite | mysql
@@ -103,7 +102,6 @@ API_RATE_LIMIT_PER_SECOND=60
 # ui container
 # -----------------------------------------------------------------------------
 # (APP_ENV / LOG_LEVEL above are reused; the ui reads its own copies of those.)
-UI_SECRET=                   # 32-byte hex; signs session cookies
 PUBLIC_URL=http://localhost:8080
 
 # Where the ui finds the api (internal docker network DNS)

+ 0 - 1
api/config/settings.php

@@ -32,7 +32,6 @@ $oidcDefaultRole = $oidcDefaultRoleName === 'none'
 return [
     'app_env' => $appEnv,
     'log_level' => $logLevel,
-    'app_secret' => getenv('APP_SECRET') ?: '',
     'db' => [
         'driver' => getenv('DB_DRIVER') ?: 'sqlite',
         'sqlite_path' => getenv('DB_SQLITE_PATH') ?: '/data/irdb.sqlite',

+ 1 - 2
api/src/Application/Admin/ConfigController.php

@@ -13,7 +13,7 @@ use Psr\Http\Message\ServerRequestInterface;
  *
  * Masking rules per SPEC §M12.5:
  *  - `***`               for: INTERNAL_JOB_TOKEN, MAXMIND_LICENSE_KEY,
- *                            IPINFO_TOKEN, DB_MYSQL_PASSWORD, APP_SECRET
+ *                            IPINFO_TOKEN, DB_MYSQL_PASSWORD
  *  - first 8 + `...`     for: UI_SERVICE_TOKEN
  *  - plain values        for everything else
  *
@@ -51,7 +51,6 @@ final class ConfigController
             'app' => [
                 'APP_ENV' => $this->settings['app_env'] ?? null,
                 'LOG_LEVEL' => $this->levelName(),
-                'APP_SECRET' => self::mask((string) ($this->settings['app_secret'] ?? '')),
                 'UI_ORIGIN' => $this->settings['ui_origin'] ?? null,
             ],
             'database' => [

+ 1 - 1
api/src/Infrastructure/Logging/SecretScrubbingProcessor.php

@@ -36,7 +36,7 @@ final class SecretScrubbingProcessor implements ProcessorInterface
      *   `password`, `password_hash`, `LOCAL_ADMIN_PASSWORD_HASH`,
      *   `oidc_client_secret`, `client_secret`,
      *   `maxmind_license_key`, `ipinfo_token`,
-     *   `db_mysql_password`, `app_secret`, `internal_job_token`,
+     *   `db_mysql_password`, `internal_job_token`,
      *   `ui_service_token`, `bearer`, `cookie`, `set-cookie`.
      */
     private const SENSITIVE_KEY_NEEDLES = [

+ 0 - 1
api/tests/Integration/Support/AppTestCase.php

@@ -71,7 +71,6 @@ abstract class AppTestCase extends TestCase
         $settings = [
             'app_env' => 'development',
             'log_level' => \Monolog\Level::Warning,
-            'app_secret' => 'test',
             'db' => [
                 'driver' => 'sqlite',
                 'sqlite_path' => $this->sqlitePath,

+ 3 - 5
doc/security.md

@@ -153,7 +153,6 @@ container environment variables, never written to the DB. The list:
 - `INTERNAL_JOB_TOKEN` — bearer for the scheduler's
   `/internal/jobs/*` calls. Network-restricted in addition to the
   token.
-- `APP_SECRET`, `UI_SECRET` — application-internal signing seeds.
 - `LOCAL_ADMIN_PASSWORD_HASH` — Argon2id hash; the raw password is
   never on disk.
 - `OIDC_CLIENT_SECRET`, `MAXMIND_LICENSE_KEY`, `IPINFO_TOKEN`,
@@ -162,10 +161,9 @@ container environment variables, never written to the DB. The list:
 
 `GET /api/v1/admin/config` (admin-only) surfaces effective
 configuration with the sensitive values masked: `INTERNAL_JOB_TOKEN`,
-`MAXMIND_LICENSE_KEY`, `IPINFO_TOKEN`, `DB_MYSQL_PASSWORD`,
-`APP_SECRET` show as `***`; `UI_SERVICE_TOKEN` shows the first 8
-characters. Empty values are visible (so misconfiguration is
-debuggable).
+`MAXMIND_LICENSE_KEY`, `IPINFO_TOKEN`, and `DB_MYSQL_PASSWORD` show
+as `***`; `UI_SERVICE_TOKEN` shows the first 8 characters. Empty
+values are visible (so misconfiguration is debuggable).
 
 ## Logging
 

+ 3 - 6
doc/user-manual.md

@@ -58,8 +58,6 @@ the key ones are:
 
 | Variable                  | How to generate                                                                                  |
 |---------------------------|--------------------------------------------------------------------------------------------------|
-| `UI_SECRET`               | `openssl rand -hex 32` — signs UI session cookies.                                               |
-| `APP_SECRET`              | `openssl rand -hex 32` — signs api-side ETags and similar.                                       |
 | `INTERNAL_JOB_TOKEN`      | `openssl rand -hex 32` — Bearer for `/internal/jobs/*`.                                          |
 | `UI_SERVICE_TOKEN`        | `irdb_svc_…` — bridge between UI and API (see `.env.example` for the one-liner).                |
 | `LOCAL_ADMIN_PASSWORD_HASH` | `php -r "echo password_hash('your-pw', PASSWORD_ARGON2ID);"` — **double every `$` to `$$`** in the .env file so docker-compose doesn't eat it. |
@@ -508,10 +506,9 @@ Three sections:
 
 The api's effective config, grouped into sections (database, jobs,
 GeoIP, etc.). Secrets are masked: `***` for `INTERNAL_JOB_TOKEN`,
-`MAXMIND_LICENSE_KEY`, `IPINFO_TOKEN`, `DB_MYSQL_PASSWORD`,
-`APP_SECRET`. `UI_SERVICE_TOKEN` is shown as the first 8 characters
-+ `…`. Empty values are rendered as `(empty)` so misconfiguration is
-visible.
+`MAXMIND_LICENSE_KEY`, `IPINFO_TOKEN`, `DB_MYSQL_PASSWORD`.
+`UI_SERVICE_TOKEN` is shown as the first 8 characters + `…`. Empty
+values are rendered as `(empty)` so misconfiguration is visible.
 
 #### Jobs
 

+ 0 - 1
ui/config/settings.php

@@ -34,7 +34,6 @@ return [
     'app_env' => $appEnv,
     'log_level' => $logLevel,
     'public_url' => getenv('PUBLIC_URL') ?: 'http://localhost:8080',
-    'ui_secret' => getenv('UI_SECRET') ?: '',
 
     // BFF — talking to the api
     'api_base_url' => getenv('API_BASE_URL') ?: '',

+ 0 - 1
ui/tests/Integration/Support/AppTestCase.php

@@ -63,7 +63,6 @@ abstract class AppTestCase extends TestCase
             'app_env' => 'development',
             'log_level' => \Monolog\Level::Warning,
             'public_url' => 'http://localhost:8080',
-            'ui_secret' => 'test',
             'api_base_url' => 'http://api:8081',
             'ui_service_token' => 'irdb_svc_TESTTOKEN',
             'api_timeout_seconds' => 1.0,