@
R6: Security - Master-Key + AES-256-GCM at-rest + TLS-Warnung - Core/Security/SecretProtection: AES-256-GCM at-rest, Master-Key aus env IBKRTRADER_MASTER_KEY bzw. gitignorierte master.key; selbstheilendes enc:v1:-Format; Passthrough ohne Key (mit Warnung) - Core/Security/EncryptedStringConverter (EF-ValueConverter, bereit fuer kuenftige Credentials) - Program: ConfigureSecretProtection (Master-Key laden) + WarnIfDbTlsNotEnforced (SslMode) beim Start - master.key gitignored - Tests: SecretProtection (Round-Trip/Idempotenz/Passthrough/Tamper/Key-Fehler) -> 56/56 gruen Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This commit is contained in:
+41
@@ -5,6 +5,7 @@ using IBKRTrader.Core.DependencyInjection;
|
||||
using IBKRTrader.Core.IBKR;
|
||||
using IBKRTrader.Core.Logging;
|
||||
using IBKRTrader.Core.Modularity;
|
||||
using IBKRTrader.Core.Security;
|
||||
using IBKRTrader.Core.Settings;
|
||||
using IBKRTrader.Core.Trading;
|
||||
using IBKRTrader.Core.Workers;
|
||||
@@ -61,6 +62,11 @@ internal static class Program
|
||||
})
|
||||
.Build();
|
||||
|
||||
// Sicherheit: Master-Key laden (VOR jeder Entschlüsselung) und DB-TLS prüfen.
|
||||
var startupLog = AppHost.Services.GetRequiredService<LoggingService>();
|
||||
ConfigureSecretProtection(startupLog);
|
||||
WarnIfDbTlsNotEnforced(AppHost.Services, startupLog);
|
||||
|
||||
// Zirkuläre Abhängigkeit auflösen: WebApiService braucht die Engine-Referenz (vor dem Start).
|
||||
AppHost.Services.GetRequiredService<WebApiService>()
|
||||
.SetEngine(AppHost.Services.GetRequiredService<WorkerEngine>());
|
||||
@@ -174,6 +180,41 @@ internal static class Program
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lädt den Master-Key (env IBKRTRADER_MASTER_KEY, sonst gitignorierte master.key) und aktiviert die
|
||||
/// at-rest-Verschlüsselung. Ohne Key läuft die App mit Klartext – mit deutlicher Warnung.
|
||||
/// </summary>
|
||||
private static void ConfigureSecretProtection(LoggingService logger)
|
||||
{
|
||||
var masterKey = Environment.GetEnvironmentVariable("IBKRTRADER_MASTER_KEY");
|
||||
if (string.IsNullOrWhiteSpace(masterKey))
|
||||
{
|
||||
var keyFile = Path.Combine(AppContext.BaseDirectory, "master.key");
|
||||
if (File.Exists(keyFile)) masterKey = File.ReadAllText(keyFile).Trim();
|
||||
}
|
||||
SecretProtection.Configure(masterKey);
|
||||
|
||||
if (SecretProtection.IsConfigured)
|
||||
logger.Info("Core", "🔐 Secret-Verschlüsselung aktiv – sensible Daten werden at-rest verschlüsselt (AES-256-GCM).");
|
||||
else
|
||||
logger.Warn("Core", "⚠️ SICHERHEIT: Kein IBKRTRADER_MASTER_KEY gesetzt – sensible Daten würden UNVERSCHLÜSSELT gespeichert. " +
|
||||
"Master-Key setzen (env IBKRTRADER_MASTER_KEY oder Datei master.key).");
|
||||
}
|
||||
|
||||
/// <summary>Warnt, wenn der DB-Connection-String keine TLS-Option (SslMode) enthält. Der String wird NICHT geloggt.</summary>
|
||||
private static void WarnIfDbTlsNotEnforced(IServiceProvider services, LoggingService logger)
|
||||
{
|
||||
try
|
||||
{
|
||||
var conn = services.GetService<IConfiguration>()?["Database:MySqlConnectionString"] ?? string.Empty;
|
||||
if (string.IsNullOrEmpty(conn)) return;
|
||||
if (conn.IndexOf("sslmode", StringComparison.OrdinalIgnoreCase) < 0)
|
||||
logger.Warn("Core", "⚠️ SICHERHEIT: DB-Verbindung ohne SslMode – Transportverschlüsselung nicht erzwungen. " +
|
||||
"Im Connection-String 'SslMode=Required' setzen.");
|
||||
}
|
||||
catch { /* best-effort, darf den Start nie stören */ }
|
||||
}
|
||||
|
||||
/// <summary>Diagnose: öffnet die DB (aus settings.json) und gibt die Serverversion aus. Kein UI.</summary>
|
||||
private static void RunDbVersion()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user