From d11834da37ea87ebbfcc409a97c4ad04aa97fd7e Mon Sep 17 00:00:00 2001 From: Falknat Date: Fri, 3 Oct 2025 01:04:50 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20vAccess=20=D0=B4=D0=BB=D1=8F=20Proxy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Теперь наши правила работают так же для Proxy серверов. --- Backend/WebServer/proxy_server.go | 8 + Backend/WebServer/vAccess.go | 211 ++++++++++++------ README.md | 50 ++++- WebServer/tools/Proxy_vAccess/README.md | 158 +++++++++++++ .../Proxy_vAccess/git.example.ru_vAccess.conf | 16 ++ 5 files changed, 378 insertions(+), 65 deletions(-) create mode 100644 WebServer/tools/Proxy_vAccess/README.md create mode 100644 WebServer/tools/Proxy_vAccess/git.example.ru_vAccess.conf diff --git a/Backend/WebServer/proxy_server.go b/Backend/WebServer/proxy_server.go index daaa179..22d5289 100644 --- a/Backend/WebServer/proxy_server.go +++ b/Backend/WebServer/proxy_server.go @@ -35,6 +35,14 @@ func StartHandlerProxy(w http.ResponseWriter, r *http.Request) (valid bool) { valid = true + // Проверяем vAccess для прокси + accessAllowed, errorPage := CheckProxyVAccess(r.URL.Path, proxyConfig.ExternalDomain, r) + if !accessAllowed { + // Доступ запрещён - обрабатываем страницу ошибки + HandleProxyVAccessError(w, r, errorPage) + return valid + } + // Проверяем AutoHTTPS - редирект с HTTP на HTTPS https_check := !(r.TLS == nil) if !https_check && proxyConfig.AutoHTTPS { diff --git a/Backend/WebServer/vAccess.go b/Backend/WebServer/vAccess.go index c8e8bb0..d2dc3ac 100644 --- a/Backend/WebServer/vAccess.go +++ b/Backend/WebServer/vAccess.go @@ -307,6 +307,103 @@ func matchExceptions(exceptions []string, requestPath string) bool { return false } +// Универсальная функция проверки правил vAccess +// Возвращает (разрешён_доступ, страница_ошибки) +func checkRules(rules []VAccessRule, requestPath string, r *http.Request, checkFileExtensions bool, logPrefix string, logFile string) (bool, string) { + // Проверяем каждое правило + for _, rule := range rules { + // Проверяем соответствие путей (если указаны) + pathMatched := true // По умолчанию true, если путей нет + if len(rule.PathAccess) > 0 { + pathMatched = false + for _, rulePath := range rule.PathAccess { + if matchPath(rulePath, requestPath) { + pathMatched = true + break + } + } + } + + // Если путь не совпадает - переходим к следующему правилу + if !pathMatched { + continue + } + + // Проверяем исключения - если путь в исключениях, пропускаем правило + if matchExceptions(rule.ExceptionsDir, requestPath) { + continue + } + + // Проверяем соответствие расширения файла (если включена проверка) + fileMatches := true // По умолчанию true + if checkFileExtensions && len(rule.TypeFile) > 0 { + fileMatches = matchFileExtension(rule.TypeFile, requestPath) + } + + // Проверяем соответствие IP адреса (если указаны) + ipMatches := true // По умолчанию true, если IP не указаны + if len(rule.IPList) > 0 { + clientIP := getClientIP(r) + ipMatches = matchIPAddress(rule.IPList, clientIP) + } + + // Применяем правило в зависимости от типа + switch rule.Type { + case "Allow": + // Allow правило: разрешаем только если ВСЕ условия выполнены + conditionsFailed := false + if checkFileExtensions && len(rule.TypeFile) > 0 && !fileMatches { + conditionsFailed = true + } + if len(rule.IPList) > 0 && !ipMatches { + conditionsFailed = true + } + + if conditionsFailed { + // Условия НЕ выполнены - блокируем + errorPage := rule.UrlError + if errorPage == "" { + errorPage = "404" + } + tools.Logs_file(1, logPrefix, "🚫 Доступ запрещён для "+getClientIP(r)+" к "+requestPath, logFile, false) + return false, errorPage + } + // Все условия Allow выполнены - разрешаем доступ + return true, "" + + case "Disable": + // Disable правило: запрещаем если ЛЮБОЕ условие выполнено + shouldBlock := true + + // Для расширений файлов (только если проверка включена) + if checkFileExtensions && len(rule.TypeFile) > 0 && !fileMatches { + shouldBlock = false + } + + // Для IP адресов + if len(rule.IPList) > 0 && !ipMatches { + shouldBlock = false + } + + if shouldBlock { + errorPage := rule.UrlError + if errorPage == "" { + errorPage = "404" + } + tools.Logs_file(1, logPrefix, "🚫 Доступ запрещён для "+getClientIP(r)+" к "+requestPath, logFile, false) + return false, errorPage + } + + default: + // Неизвестный тип правила - игнорируем + continue + } + } + + // Все проверки пройдены - разрешаем доступ + return true, "" +} + // Основная функция проверки доступа // Возвращает (разрешён_доступ, страница_ошибки) func CheckVAccess(requestPath string, host string, r *http.Request) (bool, string) { @@ -326,70 +423,10 @@ func CheckVAccess(requestPath string, host string, r *http.Request) (bool, strin continue } - // Проверяем каждое правило в конфиге - for _, rule := range config.Rules { - // Проверяем соответствие путей (если указаны) - pathMatched := true // По умолчанию true, если путей нет - if len(rule.PathAccess) > 0 { - pathMatched = false - for _, rulePath := range rule.PathAccess { - if matchPath(rulePath, requestPath) { - pathMatched = true - break - } - } - } - - // Если путь не совпадает - переходим к следующему правилу - if !pathMatched { - continue - } - - // Проверяем исключения - если путь в исключениях, пропускаем правило - if matchExceptions(rule.ExceptionsDir, requestPath) { - continue - } - - // Проверяем соответствие расширения файла (если указаны) - fileMatches := true // По умолчанию true, если типов файлов нет - if len(rule.TypeFile) > 0 { - fileMatches = matchFileExtension(rule.TypeFile, requestPath) - } - - // Проверяем соответствие IP адреса (если указаны) - ipMatches := true // По умолчанию true, если IP не указаны - if len(rule.IPList) > 0 { - clientIP := getClientIP(r) - ipMatches = matchIPAddress(rule.IPList, clientIP) - } - - // Применяем правило в зависимости от типа - switch rule.Type { - case "Allow": - // Allow правило: разрешаем только если ВСЕ условия выполнены - if (len(rule.TypeFile) > 0 && !fileMatches) || (len(rule.IPList) > 0 && !ipMatches) { - // Условия НЕ выполнены - блокируем - errorPage := rule.UrlError - if errorPage == "" { - errorPage = "404" // По умолчанию 404 - } - return false, errorPage - } - // Все условия Allow выполнены - разрешаем доступ - return true, "" - case "Disable": - // Disable правило: запрещаем если ЛЮБОЕ условие выполнено - if (len(rule.TypeFile) == 0 || fileMatches) && (len(rule.IPList) == 0 || ipMatches) { - errorPage := rule.UrlError - if errorPage == "" { - errorPage = "404" // По умолчанию 404 - } - return false, errorPage - } - default: - // Неизвестный тип правила - игнорируем - continue - } + // Используем универсальную функцию проверки правил (с проверкой расширений файлов) + allowed, errorPage := checkRules(config.Rules, requestPath, r, true, "vAccess", "logs_vaccess.log") + if !allowed { + return false, errorPage } } @@ -420,3 +457,49 @@ func HandleVAccessError(w http.ResponseWriter, r *http.Request, errorPage string } } } + +// ======================================== +// ФУНКЦИИ ДЛЯ ПРОКСИ-СЕРВЕРА +// ======================================== + +// Основная функция проверки доступа для прокси-сервера +// Возвращает (разрешён_доступ, страница_ошибки) +func CheckProxyVAccess(requestPath string, domain string, r *http.Request) (bool, string) { + // Путь к конфигурационному файлу прокси + configPath := "WebServer/tools/Proxy_vAccess/" + domain + "_vAccess.conf" + + // Проверяем существование файла + if _, err := os.Stat(configPath); os.IsNotExist(err) { + // Нет конфигурационного файла - разрешаем доступ + return true, "" + } + + // Парсим конфигурационный файл + config, err := parseVAccessFile(configPath) + if err != nil { + tools.Logs_file(1, "vAccess-Proxy", "❌ Ошибка парсинга "+configPath+": "+err.Error(), "logs_vaccess_proxy.log", false) + return true, "" // При ошибке парсинга разрешаем доступ + } + + // Используем универсальную функцию проверки правил (с проверкой расширений файлов) + return checkRules(config.Rules, requestPath, r, true, "vAccess-Proxy", "logs_vaccess_proxy.log") +} + +// Обработка страницы ошибки vAccess для прокси +func HandleProxyVAccessError(w http.ResponseWriter, r *http.Request, errorPage string) { + switch { + case errorPage == "404": + // Стандартная 404 страница + w.WriteHeader(http.StatusForbidden) + http.ServeFile(w, r, "WebServer/tools/error_page/index.html") + + case strings.HasPrefix(errorPage, "http://") || strings.HasPrefix(errorPage, "https://"): + // Внешний сайт - редирект + http.Redirect(w, r, errorPage, http.StatusFound) + + default: + // Для прокси возвращаем 403 Forbidden + w.WriteHeader(http.StatusForbidden) + http.ServeFile(w, r, "WebServer/tools/error_page/index.html") + } +} diff --git a/README.md b/README.md index bcc3345..ef91977 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - ✅ **Proxy сервер** для проксирования запросов - ✅ **PHP сервер** со встроенной поддержкой PHP 8 - ✅ **Статический контент** для размещения веб-сайтов +- ✅ **vAccess** - система контроля доступа для сайтов и прокси ### 🗄️ База данных - ✅ **MySQL сервер** с полной поддержкой @@ -158,6 +159,52 @@ go build -o MyApp.exe - Введите команду `config_reload` в консоли для перезагрузки конфигурации - Изменения применятся к новым запросам без перезапуска сервера +## 🔒 vAccess - Система контроля доступа + +vServer включает гибкую систему контроля доступа **vAccess** для сайтов и прокси-сервисов. + +### 📁 Расположение конфигураций + +**Для сайтов:** +``` +WebServer/www/{host}/vAccess.conf +``` + +**Для прокси:** +``` +WebServer/tools/Proxy_vAccess/{domain}_vAccess.conf +``` + +### ⚙️ Основные возможности + +- ✅ **IP-фильтрация** - разрешение/блокировка по IP адресам +- ✅ **Контроль путей** - ограничение доступа к определённым директориям +- ✅ **Фильтрация файлов** - блокировка по расширениям (*.php, *.exe) +- ✅ **Исключения** - гибкие правила с exceptions_dir +- ✅ **Кастомные ошибки** - редиректы или страницы ошибок + +### 📝 Пример конфигурации + +```conf +# Разрешаем админку только с локальных IP +type: Allow +path_access: /admin/*, /api/admin/* +ip_list: 127.0.0.1, 192.168.1.100 +url_error: 404 + +# Блокируем опасные файлы в uploads +type: Disable +type_file: *.php, *.exe, *.sh +path_access: /uploads/* +url_error: 404 +``` + +### 📚 Документация + +Подробная документация по vAccess: +- **Для сайтов:** см. `WebServer/www/{host}/vAccess.conf` (примеры в файле) +- **Для прокси:** см. `WebServer/tools/Proxy_vAccess/README.md` + ## 📝 Логирование Все логи сохраняются в `WebServer/tools/logs/`: @@ -168,7 +215,8 @@ go build -o MyApp.exe - 🗄️ `logs_mysql.log` - MySQL операции - 🐘 `logs_php.log` - PHP ошибки - ⚙️ `logs_config.log` - Конфигурация -- 🔒 `logs_vaccess.log` - Контроль доступа +- 🔐 `logs_vaccess.log` - Контроль доступа для сайтов +- 🔐 `logs_vaccess_proxy.log` - Контроль доступа для прокси ## 🔐 SSL Сертификаты diff --git a/WebServer/tools/Proxy_vAccess/README.md b/WebServer/tools/Proxy_vAccess/README.md new file mode 100644 index 0000000..348fc8b --- /dev/null +++ b/WebServer/tools/Proxy_vAccess/README.md @@ -0,0 +1,158 @@ +# 🔒 vAccess для Proxy-сервиса + +Система контроля доступа для прокси-сервера, аналогичная vAccess для веб-сайтов. + +## 📁 Структура + +``` +Proxy_vAccess/ +├── _example_vAccess.conf - Пример конфигурации с комментариями +├── {domain}_vAccess.conf - Конфигурация для конкретного домена +└── README.md - Эта документация +``` + +## 🚀 Как использовать + +### 1. Создание конфигурации + +Для каждого прокси-домена создайте файл: +``` +{ExternalDomain}_vAccess.conf +``` + +**Пример:** +- `git.example.ru_vAccess.conf` +- `api.myservice.com_vAccess.conf` +- `proxy.domain.org_vAccess.conf` + +### 2. Синтаксис конфигурации + +Каждый блок правил начинается с комментария `#`: + +```conf +# Описание правила +type: Allow | Disable +path_access: /path1/*, /path2/* +ip_list: 192.168.1.1, 127.0.0.1 +exceptions_dir: /public/* +url_error: 404 | https://site.com | /error.html +``` + +## 📋 Параметры правил + +| Параметр | Обязательный | Описание | +|----------|--------------|----------| +| `type` | ✅ Да | `Allow` - разрешить доступ, `Disable` - запретить | +| `type_file` | ❌ Нет | Расширения файлов через запятую (*.json, *.pdf) | +| `path_access` | ❌ Нет | Список путей через запятую | +| `ip_list` | ❌ Нет | Список IP адресов через запятую | +| `exceptions_dir` | ❌ Нет | Пути-исключения (правило не применяется) | +| `url_error` | ❌ Нет | Страница ошибки при блокировке | + +## 🔍 Примеры использования + +### Пример 1: Админка только с локальных IP +```conf +# Разрешаем админку только с определённых IP +type: Allow +path_access: /admin/*, /api/admin/* +ip_list: 127.0.0.1, 192.168.1.100 +url_error: 404 +``` + +### Пример 2: Блокировка определённых IP +```conf +# Блокируем подозрительные IP для всего сервиса +type: Disable +ip_list: 10.0.0.50, 192.168.1.200 +url_error: https://example.com/blocked +``` + +### Пример 3: Защита внутренних API +```conf +# Блокируем доступ к служебным API +type: Disable +path_access: /internal/*, /private/* +exceptions_dir: /internal/health +url_error: 404 +``` + +### Пример 4: Доступ только с локальной сети +```conf +# Разрешаем доступ к API только с локальных адресов +type: Allow +path_access: /api/* +ip_list: 127.0.0.1, ::1, 192.168.0.0/16 +url_error: 404 +``` + +### Пример 5: Блокировка опасных файлов +```conf +# Блокируем исполняемые файлы через прокси +type: Disable +type_file: *.php, *.exe, *.sh, *.bat +path_access: /uploads/*, /files/* +url_error: 404 +``` + +### Пример 6: Разрешить только определённые типы +```conf +# В API разрешаем только JSON и XML +type: Allow +type_file: *.json, *.xml, no_extension +path_access: /api/* +url_error: 404 +``` + +### Пример 7: Блокировка архивов +```conf +# Блокируем скачивание архивов с приватных путей +type: Disable +type_file: *.zip, *.rar, *.7z, *.tar.gz +path_access: /downloads/private/* +exceptions_dir: /downloads/private/public/* +url_error: https://example.com/access-denied +``` + +## ⚙️ Логика работы + +1. **Порядок проверки:** правила проверяются сверху вниз +2. **Первое совпадение:** первое подходящее правило срабатывает +3. **Нет конфига = доступ разрешён:** если файла нет, доступ не ограничен +4. **Allow правило:** доступ разрешён ТОЛЬКО если ВСЕ условия выполнены +5. **Disable правило:** доступ запрещён если ЛЮБОЕ условие выполнено + +## 📊 Логирование + +Все события vAccess для прокси записываются в: +``` +WebServer/tools/logs/logs_vaccess_proxy.log +``` + +Формат логов: +``` +[2025-10-03 00:45:23] [vAccess-Proxy] 🚫 Доступ запрещён для 192.168.1.50 к git.example.ru/admin +``` + +## 🔗 Связь с основной системой + +vAccess для прокси использует **ту же кодовую базу**, что и vAccess для сайтов: +- Все функции парсинга, проверки IP, путей общие +- Изменения в логике автоматически применяются везде +- Единый стиль конфигурации + +## ⚠️ Важные замечания + +1. **IP-адреса берутся из соединения** (не из заголовков прокси) +2. **Порядок правил важен** - специфичные правила размещайте ВЫШЕ общих +3. **Проверка расширений работает** - можно фильтровать по type_file даже для прокси +4. **Поддержка подсетей:** можно использовать CIDR нотацию (192.168.0.0/24) +5. **Множественные расширения:** поддержка файлов типа .tar.gz, .backup.sql + +## 📞 Поддержка + +При ошибках парсинга конфигурации: +1. Проверьте синтаксис в `_example_vAccess.conf` +2. Убедитесь что у правила есть `type:` и хотя бы одно условие +3. Посмотрите логи в `logs_vaccess_proxy.log` + diff --git a/WebServer/tools/Proxy_vAccess/git.example.ru_vAccess.conf b/WebServer/tools/Proxy_vAccess/git.example.ru_vAccess.conf new file mode 100644 index 0000000..5e4f538 --- /dev/null +++ b/WebServer/tools/Proxy_vAccess/git.example.ru_vAccess.conf @@ -0,0 +1,16 @@ +# ======================================== +# vAccess Configuration для git.example.ru +# Система контроля доступа для прокси-сервиса +# ======================================== + +# Правило 1: Разрешаем доступ к админке только с конкретныхлокальных адресов +type: Allow +path_access: /admin/*, /-/admin/* +ip_list: 127.0.0.1, 192.168.1.0 +url_error: 404 + +# Правило 2: Блокируем доступ к служебным API +type: Disable +path_access: /api/internal/*, /-/metrics/* +url_error: 404 +