Назад до журналу
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