# ПЛАН РЕАЛИЗАЦИИ БЕЗОПАСНОСТИ ДАННЫХ В ПОСТАВКАХ ## 🎯 ОБЗОР ПЛАНА План поэтапной реализации системы безопасности данных в поставках с минимальными рисками для существующей функциональности. ### КЛЮЧЕВЫЕ ПРИНЦИПЫ РЕАЛИЗАЦИИ: 1. **Постепенное внедрение** - каждая фаза независима и тестируема 2. **Обратная совместимость** - не ломаем существующий функционал 3. **Мониторинг на каждом этапе** - отслеживаем влияние изменений 4. **Откат при проблемах** - возможность быстро вернуться к предыдущей версии ## 📅 TIMELINE И ПРИОРИТЕТЫ | Фаза | Название | Длительность | Приоритет | Риски | | --------- | --------------------------- | ------------- | -------------- | ------- | | **1** | Подготовка инфраструктуры | 2-3 дня | 🔴 Критический | Низкие | | **2** | Базовые классы безопасности | 3-4 дня | 🔴 Критический | Низкие | | **3** | Обновление резолверов | 5-7 дней | 🔴 Критический | Средние | | **4** | Система аудита | 2-3 дня | 🟡 Высокий | Низкие | | **5** | Тестирование | 3-4 дня | 🟡 Высокий | Низкие | | **6** | Оптимизация | 2-3 дня | 🟢 Средний | Низкие | | **ИТОГО** | | **17-24 дня** | | | ## 🛠️ ФАЗА 1: ПОДГОТОВКА ИНФРАСТРУКТУРЫ (2-3 дня) ### Цель: Подготовить кодовую базу для внедрения безопасности без нарушения работы системы. ### Задачи: #### 1.1 Создание структуры директорий ```bash src/ ├── graphql/ │ ├── security/ # Новая папка для безопасности │ │ ├── index.ts # Экспорт всех модулей │ │ ├── supply-data-filter.ts │ │ ├── participant-isolation.ts │ │ ├── recipe-access-control.ts │ │ ├── commercial-data-audit.ts │ │ └── types.ts # Типы для безопасности │ └── resolvers/ │ └── supply-orders/ # Рефакторинг резолверов │ ├── queries.ts │ ├── mutations.ts │ └── helpers.ts ``` #### 1.2 Создание feature flag для постепенного внедрения ```typescript // src/config/features.ts export const FEATURE_FLAGS = { SUPPLY_DATA_SECURITY: { enabled: process.env.ENABLE_SUPPLY_SECURITY === 'true', auditEnabled: process.env.ENABLE_SECURITY_AUDIT === 'true', strictMode: process.env.SECURITY_STRICT_MODE === 'true', }, } // Использование в коде if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) { // Новая логика безопасности return SupplyDataFilter.filterByRole(data, userRole) } else { // Старая логика return data } ``` #### 1.3 Настройка логирования для отладки ```typescript // src/lib/security-logger.ts export class SecurityLogger { private static readonly DEBUG = process.env.SECURITY_DEBUG === 'true' static logDataAccess(params: { userId: string; action: string; resource: string; filtered: boolean }) { if (this.DEBUG) { console.log('[SECURITY]', { ...params, timestamp: new Date().toISOString(), }) } } } ``` #### 1.4 Создание миграции БД для аудита (без применения) ```sql -- prisma/migrations/add_audit_log_table.sql CREATE TABLE "AuditLog" ( "id" TEXT NOT NULL, "userId" TEXT NOT NULL, "organizationType" TEXT NOT NULL, "action" TEXT NOT NULL, "resourceType" TEXT NOT NULL, "resourceId" TEXT, "metadata" JSONB DEFAULT '{}', "ipAddress" TEXT, "userAgent" TEXT, "timestamp" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id") ); CREATE INDEX "AuditLog_userId_idx" ON "AuditLog"("userId"); CREATE INDEX "AuditLog_timestamp_idx" ON "AuditLog"("timestamp"); CREATE INDEX "AuditLog_action_idx" ON "AuditLog"("action"); ``` ### Результаты фазы 1: - ✅ Структура готова для новых классов - ✅ Feature flags позволяют безопасное тестирование - ✅ Логирование настроено для отладки - ✅ Миграция БД подготовлена ## 🔐 ФАЗА 2: БАЗОВЫЕ КЛАССЫ БЕЗОПАСНОСТИ (3-4 дня) ### Цель: Реализовать основные классы фильтрации данных с полным покрытием тестами. ### Задачи: #### 2.1 Создание типов безопасности ```typescript // src/graphql/security/types.ts export interface SecurityContext { user: { id: string organizationId: string organizationType: OrganizationType } ipAddress?: string userAgent?: string } export interface FilteredData { data: T filtered: boolean removedFields: string[] } export type DataAccessLevel = 'FULL' | 'PARTIAL' | 'NONE' ``` #### 2.2 Реализация SupplyDataFilter ```typescript // src/graphql/security/supply-data-filter.ts export class SupplyDataFilter { // Статические методы для фильтрации static filterSupplyOrder(order: SupplyOrder, context: SecurityContext): FilteredData> { const { organizationType, organizationId } = context.user // Логика фильтрации по ролям switch (organizationType) { case 'SELLER': return this.filterForSeller(order, organizationId) case 'WHOLESALE': return this.filterForWholesale(order, organizationId) case 'FULFILLMENT': return this.filterForFulfillment(order, organizationId) case 'LOGIST': return this.filterForLogist(order, organizationId) default: throw new GraphQLError('Unauthorized organization type') } } // Приватные методы для каждой роли private static filterForSeller(/*...*/) { /*...*/ } private static filterForWholesale(/*...*/) { /*...*/ } private static filterForFulfillment(/*...*/) { /*...*/ } private static filterForLogist(/*...*/) { /*...*/ } } ``` #### 2.3 Реализация ParticipantIsolation ```typescript // src/graphql/security/participant-isolation.ts export class ParticipantIsolation { static async checkAccess( prisma: PrismaClient, context: SecurityContext, resourceId: string, resourceType: 'SUPPLY_ORDER' | 'PRODUCT' | 'SERVICE', ): Promise { // Проверка доступа к ресурсу const hasAccess = await this.validateResourceAccess(prisma, context, resourceId, resourceType) if (!hasAccess) { // Логируем попытку несанкционированного доступа await CommercialDataAudit.logUnauthorizedAccess({ ...context, resourceId, resourceType, }) } return hasAccess } } ``` #### 2.4 Создание тестов для классов ```typescript // src/graphql/security/__tests__/supply-data-filter.test.ts describe('SupplyDataFilter', () => { describe('filterForFulfillment', () => { it('should hide product prices from fulfillment', () => { const order = createMockSupplyOrder() const context = createMockContext('FULFILLMENT') const filtered = SupplyDataFilter.filterSupplyOrder(order, context) expect(filtered.data.items[0].price).toBeNull() expect(filtered.data.productPrice).toBeNull() expect(filtered.removedFields).toContain('productPrice') }) it('should show recipe to fulfillment', () => { const order = createMockSupplyOrder() const context = createMockContext('FULFILLMENT') const filtered = SupplyDataFilter.filterSupplyOrder(order, context) expect(filtered.data.items[0].recipe).toBeDefined() expect(filtered.data.items[0].recipe.services).toHaveLength(2) }) }) }) ``` ### Результаты фазы 2: - ✅ Базовые классы реализованы - ✅ 100% покрытие тестами - ✅ Готовы к интеграции в резолверы ## 🔄 ФАЗА 3: ОБНОВЛЕНИЕ РЕЗОЛВЕРОВ (5-7 дней) ### Цель: Интегрировать классы безопасности в существующие GraphQL резолверы с минимальным риском. ### Задачи: #### 3.1 Создание обертки для безопасных резолверов ```typescript // src/graphql/security/secure-resolver.ts export function createSecureResolver( resolver: (parent: any, args: TArgs, context: Context) => Promise, options: { resourceType: string requiredRole?: OrganizationType[] auditAction: string }, ) { return async (parent: any, args: TArgs, context: Context): Promise => { // Проверка аутентификации if (!context.user) { throw new GraphQLError('Authentication required') } // Проверка роли если требуется if (options.requiredRole && !options.requiredRole.includes(context.user.organizationType)) { throw new GraphQLError('Insufficient permissions') } // Логирование доступа if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.auditEnabled) { await CommercialDataAudit.logAccess({ userId: context.user.id, organizationType: context.user.organizationType, action: options.auditAction, resourceType: options.resourceType, metadata: { args }, }) } // Выполнение оригинального резолвера const result = await resolver(parent, args, context) // Фильтрация результата если включена безопасность if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) { return filterResultByRole(result, context) } return result } } ``` #### 3.2 Постепенное обновление резолверов ```typescript // src/graphql/resolvers/supply-orders/queries.ts export const supplyOrderQueries = { // Старый резолвер mySupplyOrders_OLD: async (parent, args, context) => { // Существующая логика }, // Новый безопасный резолвер mySupplyOrders: createSecureResolver( async (parent, args, context) => { // Получаем данные const orders = await prisma.supplyOrder.findMany({ where: buildWhereClause(context.user, args), include: fullInclude, }) // Фильтруем если безопасность включена if (FEATURE_FLAGS.SUPPLY_DATA_SECURITY.enabled) { return orders.map((order) => SupplyDataFilter.filterSupplyOrder(order, context).data) } return orders }, { resourceType: 'SUPPLY_ORDER', auditAction: 'VIEW_SUPPLY_ORDERS', }, ), } ``` #### 3.3 A/B тестирование с метриками ```typescript // src/graphql/security/metrics.ts export class SecurityMetrics { static async compareResults(oldResult: any, newResult: any, context: SecurityContext) { const differences = this.findDifferences(oldResult, newResult) if (differences.length > 0) { await this.logDifferences({ userId: context.user.id, organizationType: context.user.organizationType, differences, timestamp: new Date(), }) } // Отправка метрик в мониторинг metrics.increment('security.filter.applied', { organizationType: context.user.organizationType, hasDifferences: differences.length > 0, }) } } ``` #### 3.4 Поэтапная миграция резолверов ```typescript // План миграции резолверов const MIGRATION_PLAN = [ // Неделя 1: Читающие запросы { resolver: 'mySupplyOrders', risk: 'LOW', rollout: '10%' }, { resolver: 'supplyOrder', risk: 'LOW', rollout: '25%' }, { resolver: 'searchSupplies', risk: 'MEDIUM', rollout: '10%' }, // Неделя 2: Мутации { resolver: 'createSupplyOrder', risk: 'HIGH', rollout: '5%' }, { resolver: 'updateSupplyOrderStatus', risk: 'HIGH', rollout: '5%' }, // Неделя 3: Полный rollout { resolver: '*', risk: 'MEDIUM', rollout: '100%' }, ] ``` ### Результаты фазы 3: - ✅ Резолверы обновлены с feature flags - ✅ A/B тестирование настроено - ✅ Метрики собираются для анализа ## 📊 ФАЗА 4: СИСТЕМА АУДИТА (2-3 дня) ### Цель: Реализовать полноценную систему аудита доступа к коммерческим данным. ### Задачи: #### 4.1 Применение миграции БД ```bash # Применяем подготовленную миграцию npx prisma migrate deploy # Обновляем Prisma Client npx prisma generate ``` #### 4.2 Реализация CommercialDataAudit ```typescript // src/graphql/security/commercial-data-audit.ts export class CommercialDataAudit { private static readonly ALERT_THRESHOLDS = { VIEW_PRICE: { perHour: 100, perDay: 500 }, VIEW_RECIPE: { perHour: 50, perDay: 200 }, BULK_EXPORT: { perHour: 5, perDay: 20 }, } static async logAccess(params: AuditParams): Promise { // Сохраняем в БД await prisma.auditLog.create({ data: { userId: params.userId, organizationType: params.organizationType, action: params.action, resourceType: params.resourceType, resourceId: params.resourceId, metadata: params.metadata || {}, ipAddress: params.ipAddress, userAgent: params.userAgent, timestamp: new Date(), }, }) // Проверяем на подозрительную активность await this.checkSuspiciousActivity(params) } private static async checkSuspiciousActivity(params: AuditParams) { const threshold = this.ALERT_THRESHOLDS[params.action] if (!threshold) return // Считаем активность за последний час const hourlyCount = await this.getActivityCount( params.userId, params.action, 60 * 60 * 1000, // 1 час ) if (hourlyCount > threshold.perHour) { await this.sendAlert({ type: 'EXCESSIVE_ACCESS', severity: 'HIGH', userId: params.userId, action: params.action, count: hourlyCount, threshold: threshold.perHour, }) } } } ``` #### 4.3 Dashboard для мониторинга ```typescript // src/pages/admin/security-audit.tsx export function SecurityAuditDashboard() { const [alerts, setAlerts] = useState([]) const [metrics, setMetrics] = useState() // Real-time подписка на алерты useEffect(() => { const subscription = subscribeToSecurityAlerts((alert) => { setAlerts(prev => [alert, ...prev]) // Показываем критичные алерты if (alert.severity === 'HIGH') { toast.error(`Security Alert: ${alert.message}`) } }) return () => subscription.unsubscribe() }, []) return (
) } ``` ### Результаты фазы 4: - ✅ Аудит логирует все обращения - ✅ Алерты работают в real-time - ✅ Dashboard для мониторинга ## ✅ ФАЗА 5: ТЕСТИРОВАНИЕ (3-4 дня) ### Цель: Обеспечить полное покрытие тестами и проверить все сценарии безопасности. ### Задачи: #### 5.1 Unit тесты для каждой роли ```typescript // src/graphql/security/__tests__/role-based-filtering.test.ts describe('Role-based filtering', () => { const testCases = [ { role: 'SELLER', canSee: ['productPrice', 'recipe', 'totalAmount'], cannotSee: [], }, { role: 'WHOLESALE', canSee: ['productPrice', 'packagesCount'], cannotSee: ['recipe', 'fulfillmentServicePrice'], }, { role: 'FULFILLMENT', canSee: ['recipe', 'fulfillmentServicePrice'], cannotSee: ['productPrice'], }, { role: 'LOGIST', canSee: ['logisticsPrice', 'routes'], cannotSee: ['productPrice', 'recipe', 'items'], }, ] testCases.forEach(({ role, canSee, cannotSee }) => { describe(`${role} role`, () => { canSee.forEach((field) => { it(`should see ${field}`, async () => { const result = await testQuery(role, SUPPLY_ORDER_QUERY) expect(result.data.supplyOrder[field]).toBeDefined() }) }) cannotSee.forEach((field) => { it(`should NOT see ${field}`, async () => { const result = await testQuery(role, SUPPLY_ORDER_QUERY) expect(result.data.supplyOrder[field]).toBeNull() }) }) }) }) }) ``` #### 5.2 Integration тесты ```typescript // src/graphql/security/__tests__/integration.test.ts describe('Supply chain security integration', () => { it('should isolate data between competitors', async () => { // Создаем двух селлеров-конкурентов const seller1 = await createTestSeller() const seller2 = await createTestSeller() // Seller1 создает поставку const supply1 = await createSupplyOrder(seller1, { productPrice: 1000, recipe: { services: ['Packing'] }, }) // Seller2 пытается получить доступ const result = await querySupplyOrder(seller2, supply1.id) expect(result.errors[0].message).toBe('Access denied') }) it('should allow partners to see limited data', async () => { const seller = await createTestSeller() const wholesale = await createTestWholesale() const fulfillment = await createTestFulfillment() // Создаем партнерства await createPartnership(seller, wholesale) await createPartnership(seller, fulfillment) // Создаем поставку const supply = await createSupplyOrder(seller, { partnerId: wholesale.id, fulfillmentCenterId: fulfillment.id, productPrice: 1000, recipe: { services: ['Packing'] }, }) // Поставщик видит свою часть const wholesaleView = await querySupplyOrder(wholesale, supply.id) expect(wholesaleView.data.productPrice).toBe(1000) expect(wholesaleView.data.recipe).toBeNull() // Фулфилмент видит свою часть const fulfillmentView = await querySupplyOrder(fulfillment, supply.id) expect(fulfillmentView.data.productPrice).toBeNull() expect(fulfillmentView.data.recipe).toBeDefined() }) }) ``` #### 5.3 Performance тесты ```typescript // src/graphql/security/__tests__/performance.test.ts describe('Security performance', () => { it('should not significantly impact query performance', async () => { const iterations = 100 // Тест без фильтрации const withoutSecurity = await measurePerformance(async () => { await queryWithoutSecurity(COMPLEX_SUPPLY_QUERY) }, iterations) // Тест с фильтрацией const withSecurity = await measurePerformance(async () => { await queryWithSecurity(COMPLEX_SUPPLY_QUERY) }, iterations) const overhead = (withSecurity.avg - withoutSecurity.avg) / withoutSecurity.avg // Допустимый overhead - 15% expect(overhead).toBeLessThan(0.15) }) }) ``` ### Результаты фазы 5: - ✅ Полное покрытие unit тестами - ✅ Integration тесты проверяют изоляцию - ✅ Performance overhead < 15% ## 🚀 ФАЗА 6: ОПТИМИЗАЦИЯ И ФИНАЛИЗАЦИЯ (2-3 дня) ### Цель: Оптимизировать производительность и подготовить к production. ### Задачи: #### 6.1 Кеширование фильтров ```typescript // src/graphql/security/cache.ts export class SecurityCache { private static cache = new LRUCache({ max: 1000, ttl: 5 * 60 * 1000, // 5 минут }) static getCacheKey(resourceId: string, userId: string, organizationType: string): string { return `${resourceId}:${userId}:${organizationType}` } static get(key: string): FilteredData | undefined { return this.cache.get(key) } static set(key: string, data: FilteredData): void { this.cache.set(key, data) } } ``` #### 6.2 Batch фильтрация ```typescript // src/graphql/security/batch-filter.ts export class BatchFilter { static async filterSupplyOrders( orders: SupplyOrder[], context: SecurityContext, ): Promise[]> { // Группируем по типам доступа const grouped = this.groupByAccessLevel(orders, context) // Применяем фильтры параллельно const filtered = await Promise.all([ this.filterFullAccess(grouped.full, context), this.filterPartialAccess(grouped.partial, context), this.filterNoAccess(grouped.none, context), ]) return filtered.flat() } } ``` #### 6.3 Документация для разработчиков ```typescript /** * @example Использование безопасных резолверов * * // Для queries * export const mySecureQuery = createSecureResolver( * async (parent, args, context) => { * // Ваша логика * }, * { * resourceType: 'SUPPLY_ORDER', * auditAction: 'VIEW_ORDERS' * } * ) * * // Для mutations * export const mySecureMutation = createSecureResolver( * async (parent, args, context) => { * // Ваша логика * }, * { * resourceType: 'SUPPLY_ORDER', * requiredRole: ['SELLER', 'WHOLESALE'], * auditAction: 'CREATE_ORDER' * } * ) */ ``` ### Результаты фазы 6: - ✅ Performance оптимизирован - ✅ Документация готова - ✅ Готово к production ## 🔍 МОНИТОРИНГ И МЕТРИКИ ### Ключевые метрики для отслеживания: ```typescript interface SecurityMetrics { // Performance метрики filteringOverhead: number // Процент замедления cacheHitRate: number // Эффективность кеша // Security метрики unauthorizedAccessAttempts: number // Попытки несанкц. доступа dataLeaksPrevented: number // Предотвращенные утечки // Business метрики affectedQueries: number // Количество затронутых запросов userComplaints: number // Жалобы пользователей } ``` ### Алерты: ```yaml alerts: - name: high_unauthorized_access condition: rate(unauthorized_access) > 10/min severity: critical - name: performance_degradation condition: filtering_overhead > 25% severity: warning - name: audit_log_failure condition: audit_write_errors > 0 severity: critical ``` ## ✅ КОНТРОЛЬНЫЙ СПИСОК ГОТОВНОСТИ ### Перед каждой фазой: - [ ] Feature flag настроен и протестирован - [ ] Rollback план готов - [ ] Метрики и логирование настроены - [ ] Команда проинформирована ### Перед production: - [ ] Все тесты проходят (unit, integration, e2e) - [ ] Performance overhead < 15% - [ ] Security review пройден - [ ] Документация обновлена - [ ] Мониторинг настроен - [ ] Support команда обучена ### После deployment: - [ ] Мониторинг метрик первые 24 часа - [ ] Анализ логов на ошибки - [ ] Feedback от пользователей - [ ] Performance отчет ## 🚨 ПЛАН ОТКАТА ### Быстрый откат (< 5 минут): ```bash # Отключение через environment ENABLE_SUPPLY_SECURITY=false ENABLE_SECURITY_AUDIT=false # Перезапуск сервисов kubectl rollout restart deployment/api-server ``` ### Полный откат (< 30 минут): ```bash # Откат к предыдущей версии kubectl rollout undo deployment/api-server # Откат миграции БД если нужно npx prisma migrate resolve --rolled-back ``` ## 📈 КРИТЕРИИ УСПЕХА 1. **Безопасность**: 0 утечек коммерческих данных 2. **Performance**: Overhead < 15% 3. **Стабильность**: 0 критических инцидентов 4. **UX**: 0 жалоб на недоступность данных 5. **Аудит**: 100% логирование критических операций --- _План разработан с учетом минимизации рисков и постепенного внедрения_ _Дата: 2025-08-22_ _Estimated effort: 17-24 дня_ _Risk level: MEDIUM с правильным подходом_