Модель безопасности
Elftia реализует многоуровневую архитектуру безопасности с глубокой эшелонированной защитой, охватывающую полную цепочку: от изоляции процессов Electron до проверки вызовов инструментов AI.
Полный конвейер безопасности
Полный конвейер безопасности для внешнего сообщения (Channel) от входа до выполнения:
flowchart TB
Input[Channel message input] --> Sanitize[InputSanitizer<br/>strip dangerous characters]
Sanitize --> Rate{RateLimiter<br/>rate check}
Rate -->|over limit| Reject1[Reject: 429]
Rate -->|pass| Permission{UserPermissionService<br/>user permissions}
Permission -->|blocked| Reject2[Reject: 403]
Permission -->|guest/moderator/admin| PG{PromptGuardian<br/>prompt injection detection}
PG -->|block mode + injection| Reject3[Reject + deflect message]
PG -->|monitor mode| Log1[Log event]
PG -->|pass| Magi[MagiService<br/>Agent processing]
Magi --> ToolCall[Tool call request]
ToolCall --> FW{ExecutionFirewall<br/>path deny list}
FW -->|deny| Block1[Deny: path blocked]
FW -->|pass| GA{GuardianAgent<br/>AI safety review}
GA -->|critical/high| Gate{ChannelPermissionGate<br/>human confirmation}
GA -->|low/none| Exec[Execute tool]
GA -->|monitor| LogExec[Log + execute]
Gate -->|approved| Exec
Gate -->|denied| Block2[Deny: user vetoed]
Exec --> Audit[AuditLogger<br/>audit record]
LogExec --> Exec
Log1 --> Magi
Основы безопасности Electron
Context Isolation
Context Isolation в Electron гарантирует, что процесс рендерера не может напрямую обращаться к Node.js API:
{/* Конфигурация безопасности при создании BrowserWindow */}
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
preload: preloadPath,
},
});
contextBridge
Скрипт preload открывает доступ только к разрешённым API через contextBridge.exposeInMainWorld():
{/* preload/index.ts -- безопасное предоставление IPC-интерфейса */}
contextBridge.exposeInMainWorld('api', {
completion: {
chatInSession: (params) => ipcRenderer.invoke('completion:chat', params),
},
});
Токен аутентификации IPC
Каждый IPC-вызов содержит токен аутентификации; главный процесс проверяет его через secureHandle:
sequenceDiagram
participant R as Renderer
participant P as Preload
participant M as Main (secureHandle)
Note over R,M: App startup
M->>P: ipcRenderer.sendSync('auth:bootstrap') returns token
P->>P: Save token to memory
Note over R,M: IPC call
R->>P: window.api.someMethod(params)
P->>M: ipcRenderer.invoke(channel, {token, ...params})
M->>M: validateToken(token)
alt Token invalid
M-->>P: throw Error('AUTH_FAILED')
else Token valid
M->>M: execute handler
M-->>P: result
end
- Генерация токена: главный процесс генерирует случайный токен при запуске
- Синхронная инициализация: preload получает токен через
sendSyncдо загрузки страницы - Проверка при каждом вызове: все IPC-вызовы, обёрнутые в
secureHandle, проверяют токен
ExecutionFirewall
Детерминированный контроль доступа по путям — блокирует доступ к системным каталогам и файлам с учётными данными. Нулевые накладные расходы на LLM.
Правила запрета
{/* Структура правила пути */}
interface DeniedPathRule {
pattern: RegExp;
reason: string;
denyOps?: ('read' | 'write')[];
}
| Категория | Примеры правил | Заблокированные операции |
|---|---|---|
| Системные каталоги | C:\Windows\, /etc/, /usr/, /proc/ | чтение + запись |
| Файлы с учётными данными | .ssh/, .aws/, .gnupg/, .env | чтение + запись |
| Данные браузера | Chrome\User Data\, .mozilla/ | чтение + запись |
| Реестр | System32\config\SAM|SYSTEM|SOFTWARE | чтение + запись |
| Конфигурационные файлы | .gitconfig, .npmrc, .bashrc | только запись |
Извлечение путей из инструментов
Автоматически извлекает пути к файлам из параметров вызова инструментов для проверки:
{/* Сопоставление инструментов с параметрами путей */}
const FILE_TOOL_PATH_PARAMS: Record<string, string[]> = {
Read: ['path', 'file_path'],
Write: ['path', 'file_path'],
Edit: ['path', 'file_path'],
ListDir: ['path', 'dir_path'],
};
{/* Интерфейс проверки межсетевого экрана */}
class ExecutionFirewall {
constructor(workspacePath: string);
checkPath(filePath: string, operation: 'read' | 'write'): FirewallCheckResult;
checkToolCall(toolName: string, toolInput: Record<string, unknown>): FirewallCheckResult;
}
interface FirewallCheckResult {
allowed: boolean;
deniedBy?: string;
reason?: string;
}
GuardianAgent
Проверщик безопасности вызовов инструментов на основе LLM, расположенный после ExecutionFirewall и перед подтверждением человеком.
Режимы работы
| Режим | Область проверки | Политика блокировки | Поведение при ошибке/таймауте |
|---|---|---|---|
off | Нет | Нет | Не запускается |
monitor | Чувствительные инструменты | Только журналирование, без блокировки | fail-open |
guard | Чувствительные инструменты | Блокировать high/critical | fail-open |
strict | Все инструменты | Блокировать medium+ | fail-closed |
Уровни риска
type RiskLevel = 'none' | 'low' | 'medium' | 'high' | 'critical';
| Уровень | Значение | Пример |
|---|---|---|
none | Полностью безопасно | Чтение файла в рабочем пространстве |
low | Незначительный риск | Запись в файл проекта |
medium | Умеренный риск | Команды Shell, изменяющие состояние, установка пакетов |
high | Высокий риск | Доступ к чувствительным путям, операции за пределами рабочего пространства |
critical | Крайне опасно | rm -rf, утечка данных, эскалация привилегий |
Критические правила
Следующие операции всегда оцениваются как high или critical:
- Удаление файлов за пределами рабочего пространства
- Рекурсивные команды удаления (
rm -rf,del /s /q,Remove-Item -Recurse) - Доступ к системным каталогам (
/etc,C:\Windows,C:\Users) - Эскалация привилегий (
sudo,runas) - Передача в shell через пайп (
curl | sh,wget | bash) - Доступ к учётным данным и ключам
Кэширование
Использует хэши SHA-256 для кэширования проверенных вызовов инструментов, избегая лишних обращений к LLM:
{/* Генерация ключа кэша GuardianAgent */}
function cacheKey(toolName: string, toolInput: unknown): string {
return createHash('sha256')
.update(JSON.stringify({ tool: toolName, input: toolInput }))
.digest('hex');
}
Список чувствительных инструментов
const SENSITIVE_TOOLS = new Set(['Bash', 'Write', 'Edit', 'Agent']);
Нечувствительные инструменты (например, Read, ListDir) пропускают проверку в режимах monitor/guard; они проверяются только в режиме strict.
PromptGuardian
Детектор инъекций промптов на основе LLM, используемый для обнаружения вредоносных инъекций в сообщениях Channel:
Режимы работы
| Режим | Поведение |
|---|---|
off | Отключён |
monitor | Обнаруживать и журналировать, не блокировать |
block | Блокировать и возвращать отклоняющее сообщение при обнаружении инъекции |
Механизм обнаружения
{/* Основной интерфейс PromptGuardian */}
class PromptGuardian {
async review(content: string, source: MessageSource): Promise<{
allowed: boolean;
isInjection: boolean;
confidence: number;
reason: string;
cached: boolean;
}>;
}
- Кэш SHA-256 для уже проверенного содержимого
- fail-open при таймауте/ошибке
- Включён только для сообщений из Channel
InputSanitizer
Санитайзер на основе регулярных выражений, удаляющий опасные символы из сообщений:
{/* Упрощённый InputSanitizer */}
class InputSanitizer {
sanitize(input: string): string;
updateConfig(config: SanitizationConfig): void;
}
Удаляемые символы:
- Символы нулевой ширины (ZWS, ZWNJ, ZWJ, ZWSP)
- Управляющие символы направления текста Unicode
- Невидимые символы форматирования
- Управляющие символы (символы новой строки и табуляции сохраняются)
RateLimiter
Ограничитель частоты запросов со скользящим окном, поддерживающий лимиты на пользователя и глобальные лимиты:
{/* Конфигурация ограничителя частоты */}
interface RateLimitConfig {
perUser: {
maxRequests: number; // default 20
windowMs: number; // default 60000 (1 minute)
};
global: {
maxRequests: number; // default 100
windowMs: number; // default 60000
};
cleanupIntervalMs: number; // expired entry cleanup interval
}
class RateLimiter {
check(userId: string): { allowed: boolean; retryAfter?: number };
updateConfig(config: Partial<RateLimitConfig>): void;
}
UserPermissionService
Управление правами пользователей Channel с поддержкой автоматической регистрации и назначения ролей:
Система ролей
| Роль | Права | Описание |
|---|---|---|
admin | Все | Администратор |
moderator | Отправка сообщений + запуск Agent'ов | Модератор |
guest | Отправка сообщений (с ограничением частоты) | Гость (роль по умолчанию) |
blocked | Нет | Заблокированный пользователь |
class UserPermissionService {
checkPermission(channelId: string, platformUserId: string): Promise<{
allowed: boolean;
role: UserRole;
user: ChannelUser;
}>;
autoRegister(channelId: string, platformUserId: string, displayName: string): Promise<ChannelUser>;
}
ChannelPermissionGate
Вызовы чувствительных инструментов из Channel требуют подтверждения пользователя:
sequenceDiagram
participant Agent as TinyElf Agent
participant Gate as PermissionGate
participant Channel as Channel Platform
participant User as Remote User
Agent->>Gate: requestPermission(toolCall)
Gate->>Gate: Generate confirmation fingerprint (SHA-256)
Gate->>Channel: Send confirmation message + fingerprint
Channel->>User: Agent wants to perform operation XX — reply YES to confirm
alt User confirms
User->>Channel: YES
Channel->>Gate: Match fingerprint
Gate-->>Agent: approved: true
else Timeout (60s)
Gate-->>Agent: approved: false, reason: timeout
else User denies
User->>Channel: NO
Gate-->>Agent: approved: false, reason: denied
end
AuditLogger
Журнал аудита безопасности, записывающий все события, связанные с безопасностью, в таблицу SQLite audit_log:
Типы событий
| Тип события | Описание | Серьёзность |
|---|---|---|
tool_executed | Вызов инструмента выполнен | info |
tool_blocked | Вызов инструмента заблокирован | warning |
tool_guardian_review | Результат проверки Guardian | info/warning |
permission_requested | Запрос подтверждения разрешения | info |
permission_granted | Разрешение одобрено | info |
permission_denied | В разрешении отказано | warning |
rate_limited | Срабатывание ограничителя частоты | warning |
injection_detected | Обнаружена инъекция промпта | critical |
user_blocked | Пользователь заблокирован | warning |
{/* Запись журнала аудита */}
interface AuditLogEntry {
id: string;
timestamp: number;
eventType: AuditEventType;
severity: 'info' | 'warning' | 'critical';
channelId?: string;
userId?: string;
toolName?: string;
details: Record<string, unknown>;
}
SecurityService / CryptoService
Сервисы шифрования на уровне приложения, защищающие чувствительные данные, хранящиеся локально:
{/* Схема шифрования */}
class SecurityService {
encrypt(plaintext: string): string; // AES-256-GCM, IV + authTag + ciphertext
decrypt(ciphertext: string): string;
}
class CryptoService {
deriveKey(password: string, salt: Buffer): Buffer;
// PBKDF2, 100K iterations, SHA-512, 32 bytes (256 bits)
}
Все API-ключи шифруются через SecurityService.encrypt() перед сохранением в SQLite.
Связанные файлы
| Файл | Описание |
|---|---|
packages/desktop/app/main/services/platform/security/ExecutionFirewall.ts | Межсетевой экран путей |
packages/desktop/app/main/services/platform/security/GuardianAgent.ts | Проверка инструментов AI |
packages/desktop/app/main/services/platform/security/PromptGuardian.ts | Обнаружение инъекций промптов |
packages/desktop/app/main/services/platform/security/RateLimiter.ts | Ограничитель частоты |
packages/desktop/app/main/services/platform/security/InputSanitizer.ts | Санитайзер входных данных |
packages/desktop/app/main/services/platform/security/UserPermissionService.ts | Права пользователей |
packages/desktop/app/main/services/platform/security/ChannelPermissionGate.ts | Шлюз подтверждения разрешений |
packages/desktop/app/main/services/platform/security/AuditLogger.ts | Журнал аудита |
packages/desktop/app/main/services/platform/security/SecurityService.ts | Шифрование AES-256-GCM |
packages/desktop/app/main/services/infra/crypto/CryptoService.ts | Получение ключей PBKDF2 |
packages/desktop/app/main/ipc/safe-handle.ts | Безопасный дескриптор IPC |
packages/desktop/app/preload/index.ts | Предоставление интерфейса contextBridge |
packages/desktop/app/shared/contracts/security-types.ts | Общие типы, связанные с безопасностью |
packages/desktop/app/main/workers/db/auditLog.ts | Операции с БД журнала аудита |
packages/desktop/app/main/workers/db/channelUsers.ts | Операции с БД пользователей Channel |