fix: Mindestlaenge fuer JWT_ACCESS_SECRET beim Start erzwungen
Backend Image / build-and-push (push) Successful in 2m13s
Frontend Image / build-and-push (push) Successful in 1m59s

JWT_ACCESS_SECRET war zwar als Pflicht-Env-Var geprueft, aber ohne
Mindestlaenge - ein kurzer/erratbarer Wert haette nicht nur das
Faelschen von Access-/MFA-/SSO-Tokens fuer jeden Nutzer erlaubt,
sondern auch (ueber mfa-crypto.util.ts, das den AES-Schluessel fuer
gespeicherte TOTP-Secrets aus genau diesem Wert ableitet) das
Entschluesseln aller gespeicherten MFA-Secrets.

main.ts bricht den Start jetzt mit klarer Fehlermeldung ab, wenn
JWT_ACCESS_SECRET kuerzer als 32 Zeichen ist. .env.example und das
K8s-Secret-Template zeigen jetzt einen ausreichend langen Platzhalter
mit Erzeugungshinweis (openssl rand -hex 32).

Betrifft nur main.ts's bootstrap() - e2e-Tests bootstrappen ueber
test/utils/create-test-app.ts direkt via configureApp() und durchlaufen
diese Pruefung nicht, daher keine Testanpassung noetig.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Sonnet 5 committed 2026-09-02 15:17:39 +02:00
1 parent 4bd7e9791a
commit 33fa768062
3 files changed
+23 -2

No files matched your search

+15
View File
@@ -5,6 +5,15 @@ import { AppModule } from './app.module';
import { configureApp } from './app.config';
const REQUIRED_ENV_VARS = ['DATABASE_URL', 'JWT_ACCESS_SECRET'] as const;
// JWT_ACCESS_SECRET is the root of trust for both authentication (every
// access/MFA-challenge/SSO-completion token is signed with it) and MFA
// secret confidentiality (mfa-crypto.util.ts derives the AES key that
// encrypts stored TOTP secrets from it) - a short or guessable value here
// would let an attacker forge tokens for any user AND decrypt everyone's
// stored TOTP secret, not just guess a password. 32 chars matches the
// output of "openssl rand -hex 32" / "-base64 32", the standard way to
// generate one.
const MIN_JWT_SECRET_LENGTH = 32;
function assertRequiredEnvVars(): void {
const missing = REQUIRED_ENV_VARS.filter((name) => !process.env[name]);
@@ -13,6 +22,12 @@ function assertRequiredEnvVars(): void {
`Missing required environment variable(s): ${missing.join(', ')}`,
);
}
const jwtSecret = process.env.JWT_ACCESS_SECRET as string;
if (jwtSecret.length < MIN_JWT_SECRET_LENGTH) {
throw new Error(
`JWT_ACCESS_SECRET must be at least ${MIN_JWT_SECRET_LENGTH} characters (got ${jwtSecret.length}) - generate one with e.g. "openssl rand -hex 32"`,
);
}
}
async function bootstrap() {