Контроль утечки данных в LLM: прокси-слой с маскированием и фильтрацией
Большие языковые модели живут «в облаке», поэтому каждый запрос с паспортными данными, номерами карт или телефонами потенциально уходит во внешний сервис и остаётся в его логах. Прокси-слой перед LLM решает эту проблему: он перехватывает исходящие запросы, находит чувствительные паттерны и маскирует их до отправки. Ниже — как собрать такой фильтр и подключить его к API-шлюзу TokenMaster.
Что понадобится
- Python 3.8+ — стандартной библиотеки достаточно, тяжёлые зависимости не нужны.
- API-ключ TokenMaster вида
sk-…— создаётся в разделе «Ключи» после регистрации на tokenmaster.ru. - Список regex-паттернов для данных, которые нельзя отдавать наружу: паспорта, карты, телефоны, email.
Собираем фильтр на Python
Начнём с функции маскирования. Она ищет в тексте знакомые форматы и заменяет их на безопасные заглушки, сохраняя полезную часть запроса:
import re
# Паттерны: паспорт РФ, банковская карта, телефон, email
PATTERNS = {
"passport": r"\b\d{4}\s?\d{6}\b",
"card": r"\b\d{4}[ -]?\d{4}[ -]?\d{4}[ -]?\d{4}\b",
"phone": r"\+?7[ (]?\d{3}[ )]?\d{3}[- ]?\d{2}[- ]?\d{2}",
"email": r"\b[\w.+-]+@[\w-]+\.[\w.]+\b",
}
def mask_text(text: str) -> str:
for kind, pattern in PATTERNS.items():
text = re.sub(
pattern,
lambda m: f"<{kind.upper()}:{len(m.group(0))} символов>",
text,
)
return text
Теперь превратим это в настоящий прокси: он принимает локальные запросы, маскирует содержимое сообщений, пишет в лог только факт обращения и размер (а не сам текст) и пересылает всё в TokenMaster.
import json
import http.server
import urllib.request
TOKENMASTER = "https://tokenmaster.ru/v1"
API_KEY = "sk-ваш-ключ"
class FilterProxy(http.server.BaseHTTPRequestHandler):
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
body = json.loads(self.rfile.read(length))
# Маскируем текст сообщений до отправки наружу
for msg in body.get("messages", []):
if isinstance(msg.get("content"), str):
msg["content"] = mask_text(msg["content"])
# Логируем только факт и размер, без содержимого
print(f"[proxy] {self.path} — {length} байт после фильтра")
req = urllib.request.Request(
TOKENMASTER + self.path,
data=json.dumps(body).encode(),
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
data = resp.read()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(data)
http.server.HTTPServer(("127.0.0.1", 8787), FilterProxy).serve_forever()
Запустите скрипт командой python proxy.py — прокси поднимется на http://127.0.0.1:8787. Все приложения внутри сети теперь ходят не напрямую в LLM, а через этот слой.
Если у вас уже стоит nginx, ту же логику можно сделать без Python — модулем Lua перехватывать тело запроса и подменять совпадения до proxy_pass на https://tokenmaster.ru/v1. Принцип одинаков: фильтр стоит перед отправкой наружу и не пропускает сырые данные.
Подключение TokenMaster
TokenMaster — это AI-шлюз с OpenAI-совместимым API, поэтому прокси не нужно адаптировать под конкретную модель:
- Base URL:
https://tokenmaster.ru/v1 - API Key: ваш ключ вида
sk-…
Прокси проксирует запросы «как есть», меняя только содержимое сообщений. Один ключ и один баланс дают доступ к нескольким семействам моделей — DeepSeek (deepseek-flash, deepseek-v4-pro), GLM / Zhipu (glm-4.5, glm-5) и Qwen. Оплата принимается из России, без привязки к зарубежной карте. Подробнее о моделях — в документации tokenmaster.ru/docs.
Проверка работы
Отправьте через прокси запрос с «запрещённым» содержимым и убедитесь, что оно ушло наружу уже в маскированном виде:
import json, urllib.request
body = {
"model": "deepseek-flash",
"messages": [
{"role": "user", "content": "Клиент: Иванов, паспорт 4512 345678, карта 4276 1234 5678 9012, тел. +7 900 123-45-67"}
],
}
req = urllib.request.Request(
"http://127.0.0.1:8787/chat/completions",
data=json.dumps(body).encode(),
headers={"Content-Type": "application/json"},
)
print(urllib.request.urlopen(req).read().decode())
В логе прокси появится строка о размере запроса, а модель получит уже <PASSPORT:11 символов> и <CARD:19 символов> вместо реальных данных. Если возникла ошибка:
- 401 / invalid api key — ключ TokenMaster неверный или скопирован не целиком (он должен начинаться с
sk-). - connection error — проверьте, что прокси пересылает запросы ровно на
https://tokenmaster.ru/v1, без лишнего/chat/completionsв Base URL. - insufficient quota — на балансе TokenMaster недостаточно средств, пополните его в разделе «Кошелёк».
Частые вопросы
Не портит ли маскирование качество ответа модели? Для большинства задач нет: модель всё равно видит тип данных и их длину, а не конкретные значения. Если для ответа реально нужны сами данные, лучше обработать их локально, а модели отдать только обезличенный результат.
Можно ли фильтровать не только текст, а целые запросы? Да. По тем же паттернам можно блокировать запрос целиком: если счётчик совпадений превысил порог, возвращать ошибку клиенту, не отправляя ничего наружу. Это удобно, когда нужно жёсткое правило, а не мягкое маскирование.
Что делать, если данные уже могли утечь раньше? Прокси защищает будущие запросы, но не отменяет прошлые. Ротация ключей API, пересмотр того, что вы отправляете моделям, и включение фильтра на уровне всей команды снижают риск повторной утечки.
Итог
Прокси-слой перед LLM — это простой и надёжный способ контролировать, какие данные уходят во внешние модели: он маскирует паспорта, карты и телефоны по regex, пишет аккуратные логи без чувствительного содержимого и не требует менять привычный код. Подключите его к шлюзу TokenMaster через Base URL https://tokenmaster.ru/v1 и ключ sk-… — и ваши запросы станут заметно безопаснее без потери удобства.
TokenMaster