Замена Google reCAPTCHA на Yandex SmartCaptcha: гайд по 152-ФЗ
- 152-ФЗ
- SmartCaptcha
- формы
- безопасность
- PSI
С 1 июля 2025 использование Google reCAPTCHA на формах сбора персональных данных в РФ — это нарушение 152-ФЗ из-за трансграничной передачи данных. Штрафы по типовым нарушениям — от 300 000 ₽ за отсутствие регистрации оператором до 15-18 млн ₽ за повторные/массовые. У нас на ozsm.ru закрыли это за один спринт (B13, 2 мая 2026): SmartCaptcha + honeypot + time-trap. Заодно — PSI Mobile на /kontakt поднялся с 89 до 100, TBT обнулился, спам прекратился полностью.
Контекст
Что именно нарушает reCAPTCHA по 152-ФЗ:
- Трансграничная передача — IP, поведение на странице, технические характеристики устройства уходят на сервера Google в США.
- БД персональных данных граждан РФ должна находиться в России — это фундаментальное требование, на которое ссылаются почти все судебные решения по штрафам.
- Скрипт reCAPTCHA подгружается до формы — даже если посетитель ничего не отправил, его данные уже улетели.
Реальные штрафы 2025-2026 (vc.ru, klerk.ru):
- 300 000 ₽ — за отсутствие регистрации оператором ПД (с 30 мая 2025)
- 1-6 млн ₽ — типовое нарушение по обработке ПД в коммерческой деятельности
- 15-18 млн ₽ — повторные и массовые нарушения
Альтернативы и почему SmartCaptcha
В России доступно три заметных решения:
- Yandex SmartCaptcha — данные хранятся в РФ, точность 99,7%, фоновый режим (
invisible) без видимого челленджа. - Капча Mail.ru — менее распространена, нет фонового режима.
- Своя капча — изображения с искажёнными буквами (старая школа). UX хуже, ML-боты ломают за минуту.
Выбрали SmartCaptcha по доступности (бесплатная для разумных объёмов), документации и работающему фоновому режиму.
B13-паттерн: lazy-load на first interaction
Главный анти-паттерн при подключении любой капчи — грузить её скрипт сразу при загрузке страницы. Это убивает PSI: на /kontakt ozsm.ru до миграции лежало ~363 КБ служебного кода Google, TBT 1648 мс.
Lazy-load по first user interaction решает обе проблемы — и юридическую (уходит трансграничный код), и performance.
<!-- На странице — placeholder без подключения скрипта -->
<form id="contact-form" data-needs-captcha>
<input type="text" name="name" required>
<input type="email" name="email" required>
<textarea name="message" required></textarea>
<!-- honeypot — невидимое поле-ловушка -->
<input type="text" name="website"
tabindex="-1"
aria-hidden="true"
autocomplete="off"
style="position:absolute;left:-9999px;opacity:0">
<!-- time-trap — отметка времени монтирования -->
<input type="hidden" name="form_ts" value="">
<div id="captcha-container"></div>
<button type="submit">Отправить</button>
</form>
<script type="module" src="/smartcaptcha-loader.js" defer></script>
// /public/smartcaptcha-loader.js
// Грузит smartcaptcha.js только при первом взаимодействии или через 8с
let loaded = false;
const trigger = () => {
if (loaded) return;
loaded = true;
const s = document.createElement('script');
s.src = 'https://smartcaptcha.yandexcloud.net/captcha.js?render=onload&onload=__sc_init__';
s.defer = true;
document.head.appendChild(s);
};
window.__sc_init__ = () => {
document.dispatchEvent(new CustomEvent('smartcaptcha:ready'));
};
// Триггеры — любое взаимодействие с формой ИЛИ 8 секунд
const events = ['focusin', 'input', 'click', 'touchstart'];
const off = events.map(e =>
document.addEventListener(e, trigger, { once: true, passive: true })
);
setTimeout(trigger, 8000);
// Заполняем form_ts при загрузке
document.querySelectorAll('input[name="form_ts"]').forEach(el => {
el.value = String(Date.now());
});
Server-side проверки: honeypot + time-trap + captcha verify
Клиент подделать тривиально. Все три проверки происходят на сервере — клиент не отвечает за безопасность.
// app/src/lib/contact-handler.ts
export interface ContactValidationDeps {
verifyCaptcha: (token: string) => Promise<boolean>;
sendEmail: (data: ContactData) => Promise<void>;
}
export async function validateAndProcessContact(
formData: FormData,
deps: ContactValidationDeps
): Promise<{ ok: true } | { ok: false; code: string }> {
// 1. honeypot — заполнено ботом
if (formData.get('website')) {
return { ok: false, code: 'honeypot' };
}
// 2. time-trap — форма отправлена быстрее, чем за 3с
const ts = Number(formData.get('form_ts') ?? 0);
if (Date.now() - ts < 3000) {
return { ok: false, code: 'too_fast' };
}
// 3. captcha — реальная проверка через Yandex API
const token = String(formData.get('smart-token') ?? '');
if (!await deps.verifyCaptcha(token)) {
return { ok: false, code: 'captcha' };
}
// 4. реальная обработка
await deps.sendEmail({
name: String(formData.get('name')),
email: String(formData.get('email')),
message: String(formData.get('message')),
});
return { ok: true };
}
Реальная имплементация verifyCaptcha:
async function verifyCaptcha(token: string): Promise<boolean> {
const res = await fetch('https://smartcaptcha.yandexcloud.net/validate', {
method: 'POST',
body: new URLSearchParams({
secret: process.env.SMARTCAPTCHA_SERVER_KEY!,
token,
ip: '0.0.0.0', // если знаем клиентский IP — передаём
}),
});
const data = await res.json();
return data.status === 'ok';
}
Результаты на ozsm.ru
Метрика на /kontakt | До миграции | После B13 |
|---|---|---|
| PSI Mobile Performance | 89 | 100 |
| TBT | 1 648 мс | 0 мс |
| Размер JS на странице | ~363 КБ Google | ~12 КБ Яндекс (lazy) |
| Спам через форму (за неделю) | 50-80 | 0 |
| Юр.риск штрафа 152-ФЗ | 1-6 млн ₽ | закрыт |
Спринт занял два дня. Из них одна задача — регистрация sitekey в Yandex Cloud (5 минут), остальное — паттерн lazy-load и server-side проверки.
Что мы из этого вынесли
- 152-ФЗ — это не косметика, а юридический риск 1-18 млн ₽. Сайт с reCAPTCHA после 1 июля 2025 — мина под бюджет. Замена занимает 1-2 дня; штраф — годовой бюджет на маркетинг.
- Защищать форму нужно тремя слоями. SmartCaptcha + honeypot + time-trap. Любой один слой пропустит 5-10% ботов; три вместе — около 0.
- Lazy-load капчи бесплатно даёт +10-20 PSI. До first interaction скрипт капчи никому не нужен — не грузите его.
Ссылки
- altcor.ru — reCAPTCHA нарушение 2025 — детальный разбор того, что именно нарушает reCAPTCHA
- klerk.ru — С 1 июля 2025 Google под запретом — официальные комментарии
- vc.ru — Персональные данные 2025: штрафы — текущие размеры штрафов
- Yandex SmartCaptcha docs — официальная документация
- Yandex Cloud — server-side validation — endpoint
/validate