S7: Zugangsdaten in Konfigurationsdateien verschluesseln
OpenRouter-Schluessel, Datenbank-Verbindungszeichenfolgen samt Passwort, Mail-Zugangsdaten und das Telegram-2FA-Passwort lagen im Klartext in AgentSettings.json und InstanceSettings.json. Wer die Dateien lesen konnte — ein Backup, eine Dateifreigabe, ein versehentlicher Commit — hatte alle Zugaenge. SecretProtector nutzt DPAPI im Benutzerkontext: Die Werte lassen sich nur vom selben Windows-Benutzer auf demselben Rechner lesen. Das schuetzt gegen Weitergabe der Datei, nicht gegen einen Angreifer, der bereits als dieser Benutzer laeuft — fuer einen lokal laufenden Dienst die angemessene Stufe. Verschluesselte Werte tragen ein Praefix. Dadurch bleibt Klartext aus bestehenden Konfigurationen lesbar und wird beim naechsten Speichern automatisch uebernommen; vorhandene Installationen laufen ohne Zutun weiter. Ein Wert, der sich nicht entschluesseln laesst — etwa nach Benutzer- oder Rechnerwechsel — wird gemeldet statt stillschweigend als Klartext durchgereicht. Sonst ginge ein unbrauchbarer Schluessel an die API und der Fehler waere schwer zuzuordnen. ConfigSecrets entscheidet anhand der Feldnamen, welche Werte betroffen sind. Das ist noetig, weil die Tool-Konfiguration ein freies Woerterbuch ist. Beim Speichern werden die Werte nur fuer den Schreibvorgang verschluesselt und danach wieder entschluesselt, damit die laufende Instanz weiterarbeiten kann. 309 Tests gruen (161 Core, 148 Tools). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
93f47aca3a
commit
8604fa30c7
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using ClawdDotNet.Core.Config;
|
||||
using ClawdDotNet.Core.Security;
|
||||
using ClawdDotNet.Models;
|
||||
|
||||
namespace ClawdDotNet.Services;
|
||||
@@ -182,7 +183,18 @@ public sealed class InstanceDirectoryManager
|
||||
public void SaveInstanceConfig(string instanceDir, InstanceConfig config)
|
||||
{
|
||||
var settingsPath = Path.Combine(instanceDir, "InstanceSettings.json");
|
||||
SaveJson(settingsPath, config);
|
||||
|
||||
// Zugangsdaten nur für das Schreiben verschlüsseln — die laufende Instanz
|
||||
// braucht sie danach wieder im Klartext.
|
||||
ConfigSecrets.Protect(config);
|
||||
try
|
||||
{
|
||||
SaveJson(settingsPath, config);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ConfigSecrets.Unprotect(config);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════
|
||||
@@ -271,6 +283,7 @@ public sealed class InstanceDirectoryManager
|
||||
var json = File.ReadAllText(settingsPath);
|
||||
config = JsonSerializer.Deserialize<AgentConfig>(json, JsonOpts) ?? new AgentConfig();
|
||||
ConfigLoader.Migrate(config);
|
||||
ConfigSecrets.Unprotect(config);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -310,7 +323,16 @@ public sealed class InstanceDirectoryManager
|
||||
public void SaveAgentSettings(string agentDir, AgentConfig config)
|
||||
{
|
||||
var settingsPath = Path.Combine(agentDir, "AgentSettings.json");
|
||||
SaveJson(settingsPath, config);
|
||||
|
||||
ConfigSecrets.Protect(config);
|
||||
try
|
||||
{
|
||||
SaveJson(settingsPath, config);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ConfigSecrets.Unprotect(config);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveAgentIdentity(string agentDir, string identity)
|
||||
|
||||
Reference in New Issue
Block a user