feat: add security system with system-wide proxy, DNS protection and encryption

- System-wide proxy: automatic Windows proxy configuration for all apps
- DNS leak protection: force all DNS queries through VPN
- Config encryption: AES-256-GCM encryption for all config files
- File protection: strict access permissions for config directory
- Leak detection: built-in security check system
- Kill Switch: temporarily disabled (will be improved in next version)

Security features:
✓ Automatic system proxy setup
✓ DNS leak protection (optional)
✓ AES-256-GCM config encryption
✓ File and directory protection
✓ Security leak checker
⚠ Kill Switch disabled (caused internet blocking issues)

Emergency recovery scripts included:
- ОТКЛЮЧИТЬ_KILLSWITCH.bat
- EMERGENCY_FIX_INTERNET.bat
- ЕСЛИ_СЛОМАЛСЯ_ИНТЕРНЕТ.txt

Documentation:
- Markdown/SECURITY_GUIDE.md - full security guide
- БЕЗОПАСНОСТЬ_БЫСТРЫЙ_СТАРТ.md - quick start guide
- CHANGELOG_SECURITY.md - detailed changelog
This commit is contained in:
2026-04-12 19:01:24 +06:00
parent 20d24a3639
commit b809e84220
18 changed files with 2063 additions and 31 deletions

View File

@@ -0,0 +1,237 @@
package security
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
// SecurityManager управляет всеми аспектами безопасности VPN
type SecurityManager struct {
killSwitch *KillSwitch
dnsProtection *DNSProtection
configDir string
password string
}
// SecurityConfig хранит настройки безопасности
type SecurityConfig struct {
KillSwitchEnabled bool `json:"kill_switch_enabled"`
DNSProtectionEnabled bool `json:"dns_protection_enabled"`
EncryptionEnabled bool `json:"encryption_enabled"`
VPNDNSServers []string `json:"vpn_dns_servers"`
AllowedVPNIPs []string `json:"allowed_vpn_ips"`
}
// NewSecurityManager создает новый менеджер безопасности
func NewSecurityManager(configDir string, password string) *SecurityManager {
return &SecurityManager{
killSwitch: NewKillSwitch(),
dnsProtection: NewDNSProtection(),
configDir: configDir,
password: password,
}
}
// LoadSecurityConfig загружает конфигурацию безопасности
func (sm *SecurityManager) LoadSecurityConfig() (*SecurityConfig, error) {
configPath := filepath.Join(sm.configDir, "security.json")
// Если файл не существует, создаем дефолтную конфигурацию с ОТКЛЮЧЕННЫМ Kill Switch
if _, err := os.Stat(configPath); os.IsNotExist(err) {
defaultConfig := &SecurityConfig{
KillSwitchEnabled: false, // ОТКЛЮЧЕНО ПО УМОЛЧАНИЮ!
DNSProtectionEnabled: true,
EncryptionEnabled: true,
VPNDNSServers: []string{"1.1.1.1", "8.8.8.8"},
AllowedVPNIPs: []string{},
}
sm.SaveSecurityConfig(defaultConfig)
return defaultConfig, nil
}
data, err := os.ReadFile(configPath)
if err != nil {
return nil, fmt.Errorf("ошибка чтения конфигурации безопасности: %w", err)
}
var config SecurityConfig
if err := json.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("ошибка парсинга конфигурации: %w", err)
}
return &config, nil
}
// SaveSecurityConfig сохраняет конфигурацию безопасности
func (sm *SecurityManager) SaveSecurityConfig(config *SecurityConfig) error {
configPath := filepath.Join(sm.configDir, "security.json")
data, err := json.MarshalIndent(config, "", " ")
if err != nil {
return fmt.Errorf("ошибка сериализации конфигурации: %w", err)
}
if err := os.WriteFile(configPath, data, 0600); err != nil {
return fmt.Errorf("ошибка сохранения конфигурации: %w", err)
}
return nil
}
// EnableProtection включает все защитные механизмы
func (sm *SecurityManager) EnableProtection(vpnInterface string, vpnServerIP string) error {
config, err := sm.LoadSecurityConfig()
if err != nil {
return err
}
// KILL SWITCH ПОЛНОСТЬЮ ОТКЛЮЧЕН - НЕ ИСПОЛЬЗУЕТСЯ!
// Оставляем только защиту DNS
// Включаем защиту DNS
if config.DNSProtectionEnabled {
if err := sm.dnsProtection.Enable(config.VPNDNSServers); err != nil {
fmt.Printf("⚠ Предупреждение: не удалось включить защиту DNS: %v\n", err)
} else {
fmt.Println("✓ Защита DNS включена (предотвращение DNS утечек)")
}
}
return nil
}
// DisableProtection отключает все защитные механизмы
func (sm *SecurityManager) DisableProtection() error {
var errors []error
// KILL SWITCH НЕ ИСПОЛЬЗУЕТСЯ - пропускаем
// Отключаем защиту DNS
if sm.dnsProtection.IsEnabled() {
if err := sm.dnsProtection.Disable(); err != nil {
errors = append(errors, fmt.Errorf("ошибка отключения защиты DNS: %w", err))
} else {
fmt.Println("✓ Защита DNS отключена")
}
}
if len(errors) > 0 {
return fmt.Errorf("ошибки при отключении защиты: %v", errors)
}
return nil
}
// EncryptConfigFile шифрует файл конфигурации
func (sm *SecurityManager) EncryptConfigFile(filePath string) error {
// Читаем файл
data, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("ошибка чтения файла: %w", err)
}
// Шифруем
encrypted, err := Encrypt(data, sm.password)
if err != nil {
return fmt.Errorf("ошибка шифрования: %w", err)
}
// Сохраняем зашифрованный файл
encryptedPath := filePath + ".encrypted"
if err := os.WriteFile(encryptedPath, []byte(encrypted), 0600); err != nil {
return fmt.Errorf("ошибка сохранения зашифрованного файла: %w", err)
}
// Безопасно удаляем оригинальный файл
if err := SecureDelete(filePath); err != nil {
return fmt.Errorf("ошибка удаления оригинального файла: %w", err)
}
// Переименовываем зашифрованный файл
if err := os.Rename(encryptedPath, filePath); err != nil {
return fmt.Errorf("ошибка переименования файла: %w", err)
}
return nil
}
// DecryptConfigFile расшифровывает файл конфигурации
func (sm *SecurityManager) DecryptConfigFile(filePath string) ([]byte, error) {
// Читаем зашифрованный файл
encryptedData, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("ошибка чтения файла: %w", err)
}
// Расшифровываем
decrypted, err := Decrypt(string(encryptedData), sm.password)
if err != nil {
return nil, fmt.Errorf("ошибка расшифровки: %w", err)
}
return decrypted, nil
}
// ProtectConfigDirectory защищает директорию с конфигурациями
func (sm *SecurityManager) ProtectConfigDirectory() error {
if err := ProtectDirectory(sm.configDir); err != nil {
return fmt.Errorf("ошибка защиты директории: %w", err)
}
fmt.Printf("✓ Директория конфигураций защищена: %s\n", sm.configDir)
return nil
}
// GetSecurityStatus возвращает текущий статус безопасности
func (sm *SecurityManager) GetSecurityStatus() map[string]interface{} {
config, _ := sm.LoadSecurityConfig()
currentDNS, _ := GetCurrentDNS()
return map[string]interface{}{
"kill_switch_enabled": sm.killSwitch.IsEnabled(),
"dns_protection_enabled": sm.dnsProtection.IsEnabled(),
"encryption_enabled": config.EncryptionEnabled,
"current_dns_servers": currentDNS,
"configured_vpn_dns": config.VPNDNSServers,
"config_dir_protected": true,
}
}
// CheckForLeaks проверяет наличие утечек
func (sm *SecurityManager) CheckForLeaks() ([]string, error) {
var leaks []string
// Проверяем DNS утечки
currentDNS, err := GetCurrentDNS()
if err == nil {
config, _ := sm.LoadSecurityConfig()
if config.DNSProtectionEnabled {
// Проверяем, что используются только VPN DNS
for _, dns := range currentDNS {
isVPNDNS := false
for _, vpnDNS := range config.VPNDNSServers {
if dns == vpnDNS {
isVPNDNS = true
break
}
}
if !isVPNDNS {
leaks = append(leaks, fmt.Sprintf("DNS утечка: используется %s вместо VPN DNS", dns))
}
}
}
}
// Проверяем Kill Switch
if !sm.killSwitch.IsEnabled() {
config, _ := sm.LoadSecurityConfig()
if config.KillSwitchEnabled {
leaks = append(leaks, "Kill Switch не активен, возможна утечка трафика при разрыве VPN")
}
}
return leaks, nil
}