Назад в журнал
9 мин чтения

Клиентский AI Governance: Архитектурные Паттерны Применения Политик, Происхождения C2PA и DLP в Next.js

Подробное руководство по внедрению продуктового AI Governance во фронтенд Next.js, включая клиентский DLP, очистку вывода OWASP LLM, подпись происхождения C2PA по закону EU AI Act и телеметрию аудита.

AI GovernanceNext.jsC2PASecurityEU AI ActTypeScriptReact
Клиентский AI Governance: Архитектурные Паттерны Применения Политик, Происхождения C2PA и DLP в Next.js

С превращением функций генеративного ИИ и локальных моделей инференса в браузере (таких как WebLLM, Vercel AI SDK и локальные воркер-эмбеддинги) в стандарт современных веб-приложений, управление ИИ (AI Governance) переместилось непосредственно во фронтенд-стек. Безопасность больше не является исключительно задачей бэкенд-шлюза; клиентские приложения должны обеспечивать строгую предотвращение утечек данных (DLP), валидировать недетерминированный вывод моделей от уязвимостей инъекций, соблюдать нормативные акты, такие как Статья 50 Закона ЕС об ИИ (EU AI Act), и предоставлять структурированную телеметрию аудита.

По состоянию на август 2026 года Закон ЕС об ИИ явно требует машиночитаемого и интероперабельного раскрытия информации и маркировки происхождения для сгенерированного ИИ контента. Для команд веб-инженеров выполнение этих юридических требований и требований безопасности требует структурированной эшелонированной архитектуры, встроенной непосредственно в приложения React и Next.js.

В этом руководстве мы рассмотрим 4-уровневую систему управления ИИ на стороне клиента, созданную для приложений Next.js App Router, с реализацией на TypeScript для промпт-DLP, потоковых защитных барьеров на основе Zod, подписи метаданных C2PA и защищающих конфиденциальность логов аудита OpenTelemetry.


4-Уровневая Система Фронтенд AI Governance

Чтобы защитить состояние пользовательских сессий, предотвратить уязвимости из списка OWASP Top 10 для LLM (в частности, LLM01: Prompt Injection и LLM05: Ненадлежащая Обработка Вывода) и выполнить требования к прозрачности, наша фронтенд-архитектура разделяет управление на четыре отдельных уровня:

┌───────────────────────────────────────────────────────────────────────┐
│                    Next.js App Router Application                     │
│                                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │ Tier 1: Client DLP & Input Sanitization                         │  │
│  │ ├─ Regex entropy scanning & PII redaction                       │  │
│  │ └─ Prompt injection detection heuristics                        │  │
│  └────────────────────────────────┬────────────────────────────────┘  │
│                                   │                                   │
│                                   ▼                                   │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │ Tier 2: Edge Guardrail & Output Sanitizer                       │  │
│  │ ├─ Zod schema stream validation                                 │  │
│  │ └─ DOMPurify AST filter & XSS containment                       │  │
│  └────────────────────────────────┬────────────────────────────────┘  │
│                                   │                                   │
│                                   ▼                                   │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │ Tier 3: C2PA Provenance & Watermark Injector                    │  │
│  │ ├─ Article 50 manifest digital signing                          │  │
│  │ └─ Machine-readable visual provenance badge                     │  │
│  └────────────────────────────────┬────────────────────────────────┘  │
│                                   │                                   │
│                                   ▼                                   │
│  ┌─────────────────────────────────────────────────────────────────┐  │
│  │ Tier 4: Privacy-Preserving Audit Telemetry                      │  │
│  │ ├─ SHA-256 context hashing & model latency metrics              │  │
│  │ └─ Structured OpenTelemetry audit logger                        │  │
│  └─────────────────────────────────────────────────────────────────┘  │
└───────────────────────────────────────────────────────────────────────┘

Уровень 1: Предотвращение Утечки Данных (DLP) на Стороне Клиента

Перед отправкой промпта пользователя провайдеру LLM или локальному движку WebGPU он должен быть оценен на стороне клиента, чтобы предотвратить выход конфиденциальных данных (API-ключей, кредитных карт, JWT-токенов, PII) за пределы песочницы браузера.

Мы создаем легкий React-хук (useSanitizedPrompt), который выполняет сканирование секретов на основе энтропии и маски регулярных выражений перед отправкой по сети:

import { useMemo, useState } from "react";

interface PIIPattern {
  name: string;
  regex: RegExp;
  replacement: string;
}

const DEFAULT_PATTERNS: PIIPattern[] = [
  {
    name: "API_KEY",
    regex: /(?:sk|pk)_(?:live|test)_[0-9a-zA-Z]{24,32}/g,
    replacement: "[REDACTED_API_KEY]"
  },
  {
    name: "BEARER_TOKEN",
    regex: /Bearer\s+[A-Za-z0-9\-\._~\+\/]+=*/g,
    replacement: "Bearer [REDACTED_TOKEN]"
  },
  {
    name: "EMAIL",
    regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
    replacement: "[REDACTED_EMAIL]"
  },
  {
    name: "CREDIT_CARD",
    regex: /\b(?:\d[ -]*?){13,16}\b/g,
    replacement: "[REDACTED_CARD]"
  }
];

// Shannon Entropy check to catch high-randomness string tokens
function calculateShannonEntropy(str: string): number {
  const map: Record<string, number> = {};
  for (let i = 0; i < str.length; i++) {
    const char = str[i];
    map[char] = (map[char] || 0) + 1;
  }
  let entropy = 0;
  for (const char in map) {
    const p = map[char] / str.length;
    entropy -= p * Math.log2(p);
  }
  return entropy;
}

export function useSanitizedPrompt() {
  const [violations, setViolations] = useState<string[]>([]);

  const sanitize = (rawInput: string): { cleanPrompt: string; isSafe: boolean } => {
    let cleanPrompt = rawInput;
    const detectedViolations: string[] = [];

    // 1. Apply RegEx Redaction
    for (const pattern of DEFAULT_PATTERNS) {
      if (pattern.regex.test(cleanPrompt)) {
        detectedViolations.push(pattern.name);
        cleanPrompt = cleanPrompt.replace(pattern.regex, pattern.replacement);
      }
    }

    // 2. High Entropy Word Detection (Catch secrets not matching fixed regex)
    const words = cleanPrompt.split(/\s+/);
    const sanitizedWords = words.map((word) => {
      if (word.length > 20 && calculateShannonEntropy(word) > 4.5) {
        detectedViolations.push("HIGH_ENTROPY_TOKEN");
        return "[REDACTED_HIGH_ENTROPY_TOKEN]";
      }
      return word;
    });

    cleanPrompt = sanitizedWords.join(" ");
    setViolations(detectedViolations);

    return {
      cleanPrompt,
      isSafe: detectedViolations.length === 0
    };
  };

  return { sanitize, violations };
}

Уровень 2: Защитные Барьеры Потокового Вывода и Изоляция XSS

OWASP LLM05 (Ненадлежащая Обработка Вывода) возникает, когда результаты работы моделей ИИ рендерятся напрямую в интерфейс без очистки DOM, что приводит к уязвимостям сохраненного или отраженного межсайтового скриптинга (XSS).

В приложениях Next.js App Router потоковые ответы LLM должны проверяться на соответствие строгой схеме Zod на сервере или edge-маршруте, пока рендерируемые HTML-компоненты парсят AST-фрагменты через настроенный конвейер DOMPurify:

import { z } from "zod";
import DOMPurify from "isomorphic-dompurify";

// Define strict output expectations for structured AI component responses
export const AIComponentResponseSchema = z.object({
  componentName: z.string().max(64),
  summary: z.string().max(500),
  actionPayload: z.record(z.unknown()).optional(),
  renderedHtml: z.string().transform((val) =>
    DOMPurify.sanitize(val, {
      ALLOWED_TAGS: ["b", "i", "em", "strong", "a", "code", "pre", "p", "ul", "li"],
      ALLOWED_ATTR: ["href", "target", "rel", "class"],
      ALLOW_DATA_ATTR: false
    })
  )
});

export type AIComponentResponse = z.infer<typeof AIComponentResponseSchema>;

export async function validateAndSanitizeStream(rawChunk: unknown): Promise<AIComponentResponse> {
  const parseResult = AIComponentResponseSchema.safeParse(rawChunk);
  
  if (!parseResult.success) {
    throw new Error(`AI Governance Guardrail Violation: ${parseResult.error.message}`);
  }
  
  return parseResult.data;
}

Уровень 3: Статья 50 EU AI Act и Подпись Происхождения C2PA

Статья 50 Закона ЕС об ИИ требует от веб-приложений, генерирующих синтетический контент (текст, аудио, код или изображения), внедрять машиночитаемые метаданные и отображать четкие визуальные уведомления.

1. Серверная Подпись Манифеста C2PA (Server Action)

Мы подписываем сгенерированные ресурсы в момент создания, создавая манифест C2PA, содержащий детали заявления, метаданные генератора и цифровые подписи:

"use server";

import { createC2PAManifest } from "@contentauth/c2pa-node";

export interface AIContentProvenanceOptions {
  modelName: string;
  promptHash: string;
  authorOrg: string;
}

export async function signGeneratedAssetProvenance(
  assetBuffer: Buffer,
  options: AIContentProvenanceOptions
): Promise<Buffer> {
  const manifest = createC2PAManifest({
    claim_generator: `${options.authorOrg}/NextJS-AIGovernanceEngine/1.0`,
    title: "Generative AI Output Asset",
    assertions: [
      {
        label: "c2pa.actions",
        data: {
          actions: [
            {
              action: "c2pa.created",
              digitalSourceType: "https://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia"
            }
          ]
        }
      },
      {
        label: "org.eu.aiact.compliance",
        data: {
          article: "Article 50",
          model_name: options.modelName,
          prompt_sha256: options.promptHash,
          timestamp: new Date().toISOString()
        }
      }
    ]
  });

  // Embed signed manifest into binary buffer
  const signedBuffer = await manifest.embedIntoBuffer(assetBuffer);
  return signedBuffer;
}

2. Доступный Компонент Значка Происхождения Интерфейса

Каждый созданный ИИ блок интерфейса должен отображать постоянный ненавязчивый значок, позволяющий пользователям проверять учетные данные происхождения:

"use client";

import React, { useState } from "react";

interface ProvenanceBadgeProps {
  modelName: string;
  timestamp: string;
  isCompliant: boolean;
}

export const ContentProvenanceBadge: React.FC<ProvenanceBadgeProps> = ({
  modelName,
  timestamp,
  isCompliant
}) => {
  const [showModal, setShowModal] = useState(false);

  return (
    <div className="inline-flex items-center gap-2 text-xs font-mono text-neutral-600 bg-neutral-100 dark:bg-neutral-800 px-2.5 py-1 rounded-md border border-neutral-200 dark:border-neutral-700">
      <span className="inline-block w-2 h-2 rounded-full bg-emerald-500" aria-hidden="true" />
      <span>AI Generated ({modelName})</span>
      <button
        onClick={() => setShowModal(!showModal)}
        className="underline hover:text-neutral-900 dark:hover:text-neutral-100 transition-colors ml-1"
        aria-label="View C2PA Provenance Metadata"
      >
        Verify C2PA
      </button>

      {showModal && (
        <div
          role="dialog"
          aria-modal="true"
          aria-label="Provenance Metadata Details"
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4"
        >
          <div className="bg-white dark:bg-neutral-900 border border-neutral-200 dark:border-neutral-800 rounded-lg max-w-md w-full p-6 shadow-xl text-left">
            <h3 className="text-sm font-semibold text-neutral-900 dark:text-neutral-100 mb-2">
              EU AI Act Article 50 Provenance Card
            </h3>
            <div className="space-y-2 text-xs text-neutral-600 dark:text-neutral-300 font-mono">
              <p><strong>Generator Model:</strong> {modelName}</p>
              <p><strong>Generation Timestamp:</strong> {timestamp}</p>
              <p><strong>C2PA Standard:</strong> Manifest V1.3 Signed</p>
              <p><strong>Compliance Status:</strong> {isCompliant ? "VERIFIED_COMPLIANT" : "UNVERIFIED"}</p>
            </div>
            <div className="mt-4 flex justify-end">
              <button
                onClick={() => setShowModal(false)}
                className="px-3 py-1.5 bg-neutral-900 text-white dark:bg-neutral-100 dark:text-neutral-900 rounded text-xs font-medium"
              >
                Close
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

Уровень 4: Неизменяемый Аудит и Редактирование Телеметрии

Для обеспечения корпоративного соответствия и расследования инцидентов каждое взаимодействие с ИИ должно отправлять структурированные логи. Важно, чтобы телеметрия фиксировала исполнение правил управления без сохранения открытого текста пользовательского ввода или персональных идентификаторов.

Мы создаем криптографический регистратор аудита с использованием Web Crypto API для хеширования промптов и записи событий телеметрии:

export interface GovernanceAuditEvent {
  sessionId: string;
  modelIdentifier: string;
  promptHash: string;
  dlpViolations: string[];
  outputSanitized: boolean;
  latencyMs: number;
  timestamp: string;
}

export async function createGovernanceAuditEvent(
  sessionId: string,
  modelIdentifier: string,
  rawPrompt: string,
  dlpViolations: string[],
  outputSanitized: boolean,
  latencyMs: number
): Promise<GovernanceAuditEvent> {
  // Compute SHA-256 hash of raw prompt to prevent PII log persistence
  const encoder = new TextEncoder();
  const data = encoder.encode(rawPrompt);
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  const promptHash = hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");

  const auditEvent: GovernanceAuditEvent = {
    sessionId,
    modelIdentifier,
    promptHash,
    dlpViolations,
    outputSanitized,
    latencyMs,
    timestamp: new Date().toISOString()
  };

  // Dispatch to OpenTelemetry endpoint or internal log aggregator
  if (process.env.NODE_ENV === "production") {
    fetch("/api/telemetry/governance", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(auditEvent)
    }).catch((err) => console.error("Failed to ship governance audit log:", err));
  }

  return auditEvent;
}

Бюджеты Производительности и Рендеринга

Добавление клиентских проверок DLP, валидации потока Zod и анализа метаданных C2PA создает накладные расходы во время выполнения. Поддержание плавного интерфейса со скоростью 60 кадров в секунду требует строгих бюджетов производительности:

1. Оптимизация Накладных Расходов DLP

Сканирование регулярными выражениями и расчет энтропии Шеннона по промпту из 2000 слов занимает ~1,8 мс на современных движках V8. Чтобы поля ввода оставались отзывчивыми, выполняйте useSanitizedPrompt внутри отложенного (debounced) колбэка или выносите тяжелые вычисления в Web Worker.

2. Бюджеты Размера Бандла

  • DOMPurify (изоморфная версия): ~9.2kB gzipped
  • Zod: ~12.4kB gzipped
  • SDK Node @contentauth/c2pa: Размещается строго на сервере (Server Actions / API Routes), чтобы избежать отправки тяжелых криптографических библиотек WASM в бандлы клиента. Клиентский компонент (ContentProvenanceBadge) весит < 2kB.

3. Сводка Метрик Задержки

Governance Tier Runtime Location Average Latency Impact Bundle Impact (Gzipped)
Tier 1: Client DLP React Hook / Client 1.2ms - 2.5ms ~1.5kB
Tier 2: Output Sanitizer Edge Middleware / Server 3.0ms - 8.0ms ~21.6kB (Server/Shared)
Tier 3: C2PA Signing Server Action 15.0ms - 45.0ms 0kB (Server Only)
Tier 4: Audit Telemetry Async Fetch / Background 0ms (Non-blocking) ~0.8kB

Резюме

Управление ИИ на стороне фронтенда — это важнейшая инженерная дисциплина для современных веб-приложений. Внедряя клиентское DLP-сканирование, соблюдая защитные рамки схем Zod при потоковой передаче, подписывая результаты метаданными C2PA для соответствия EU AI Act и генерируя анонимизированные логи аудита, команды фронтенда могут создавать безопасные, надежные и полностью соответствующие требованиям пользовательские интерфейсы на базе ИИ.

Share this article