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

С превращением функций генеративного ИИ и локальных моделей инференса в браузере (таких как 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 gzippedZod: ~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 и генерируя анонимизированные логи аудита, команды фронтенда могут создавать безопасные, надежные и полностью соответствующие требованиям пользовательские интерфейсы на базе ИИ.