[{"data":1,"prerenderedAt":232},["ShallowReactive",2],{"project-ru-form-protection":3,"recommendation-mention-sources":170},{"id":4,"title":5,"body":6,"category":136,"context":137,"cover":138,"coverAlt":139,"demo":140,"description":141,"extension":142,"featured":143,"locale":144,"meta":145,"navigation":146,"order":147,"path":148,"published":146,"repository":140,"results":149,"role":159,"seo":160,"slug":161,"stack":162,"stem":167,"year":168,"__hash__":169},"projects\u002Fru\u002Fprojects\u002Fform-protection.md","Защита от ботов для оформления заказа и форм покупателей",{"type":7,"value":8,"toc":120},"minimark",[9,14,18,21,25,28,32,37,40,44,47,51,54,57,61,69,73,76,79,83,113,117],[10,11,13],"h2",{"id":12},"задача","Задача",[15,16,17],"p",{},"В магазинах на inSales покупатели через формы оформляют заказы, входят в кабинет, регистрируются, восстанавливают доступ, пишут отзывы и обращения. Владельцы магазинов входят в свой аккаунт платформы. Всё это интересно ботам: при атаке они могли создавать сотни заказов в секунду. При этом защита не должна мешать живому покупателю нажать «Отправить» и оформить заказ.",[15,19,20],{},"Раньше перед отправкой нужно было отметить «Я не робот». В 2025 году продуктовая команда принесла вторую проблему: клиентов беспокоило, что персональные данные обрабатывает зарубежный сервис, а у части покупателей Google не открывался. Нужна была альтернатива, которую магазин включает одной настройкой, без переделки каждой формы. Сложность была в самой платформе. Формы жили в двух поколениях личного кабинета, трёх поколениях оформления заказа, серверных шаблонах, Vue-приложениях, штатных виджетах и в коде, который клиенты правили сами. Часто несколько форм оказывались на одной странице.",[10,22,24],{"id":23},"моя-роль","Моя роль",[15,26,27],{},"Frontend был на мне: точки интеграции, общий код и компоненты, тестовые сборки, сопровождение QA, выпуск и поддержка после релиза. Проверку токена на сервере делали backend-разработчики, контракты запросов я согласовывал с ними. За пределами фронтенда сделал одну точечную правку в Rails. Google-этап выпустил в 2023 году, выбор провайдера добавил в 2025-м (основной релиз 26 августа 2025 года), сопровождение продолжалось и в 2026-м.",[10,29,31],{"id":30},"что-я-сделал","Что я сделал",[33,34,36],"h3",{"id":35},"проверка-стала-частью-отправки","Проверка стала частью отправки",[15,38,39],{},"Я встроил Google reCAPTCHA Invisible в существующую отправку форм. Форма проверяет поля как обычно, ждёт токен капчи и только потом отправляется, а сервер проверяет токен и решает, принимать ли запрос. Сервис по-прежнему может показать задание, если ему это нужно. Для AJAX-форм сделал отдельное продолжение отправки, чтобы они не превращались в переход на другую страницу. Прежние правила сохранились: при входе по паролю капча нужна только после нескольких неудачных попыток, а у входа по одноразовому коду свои формы и обработчики.",[33,41,43],{"id":42},"ответ-капчи-относится-к-одной-форме","Ответ капчи относится к одной форме",[15,45,46],{},"Покупатель открывает форму обратной связи, запускает проверку и закрывает задание. Потом отправляет отзыв и проходит проверку уже там. Если оба обработчика ждут одно общее событие, токен от отзыва может отправить форму обратной связи. В ранней версии всё усугубляла шина событий: новому подписчику она могла вернуть старые данные. Я привязал обработчик проверки к конкретной форме вместе с её экземпляром капчи и токеном.",[33,48,50],{"id":49},"одна-настройка-и-три-слоя-интеграции","Одна настройка и три слоя интеграции",[15,52,53],{},"Я предложил настройку типа капчи в настройках магазина и выпускал её под фича-флагом. С бэкендом договорился, как передавать значение в Liquid-шаблоны, чтобы системные формы, библиотека и виджеты темы читали одно и то же. Новый провайдер подхватывается после перезагрузки страницы: открытая форма не меняет сервис посреди заполнения.",[15,55,56],{},"Интеграцию сделал в трёх местах, по устройству платформы. В CommonJS, общей JavaScript-библиотеке витрин, — модуль для 4 семейств форм: обратная связь, отзывы, комментарии, заказ в один клик. Для личных кабинетов и оформления заказа 1.0 и 2.0 — переиспользуемые Slim-шаблоны. Для checkout 3.0 и входа владельцев магазинов — Vue-компонент. Отрисовка, получение токена и отправка остались отдельными шагами, поэтому форма, которую отправляет собственный скрипт, может включить только отрисовку.",[33,58,60],{"id":59},"один-скрипт-на-страницу","Один скрипт на страницу",[15,62,63,64,68],{},"SmartCaptcha могли подключить и системная форма, и виджет магазина. Повторная загрузка создавала новый ",[65,66,67],"code",{},"window.smartCaptcha",", который ничего не знал об уже отрисованных экземплярах. Покупатель видел кнопку «Отправить», которая не работала, причём только при определённом порядке загрузки частей страницы. Я доработал загрузчики в шаблонах и библиотеке: если скрипт уже есть на странице, он используется повторно.",[33,70,72],{"id":71},"сбои-и-старые-аккаунты","Сбои и старые аккаунты",[15,74,75],{},"Если покупатель закрывал задание, форма так и оставалась в состоянии отправки. Я сделал так, что закрытие сбрасывает это состояние и можно попробовать ещё раз. При повторной попытке и после долгого ожидания форма получает свежий токен. Первую выкатку системных форм в августе 2025 года пришлось откатить: в части старых магазинов капча не появлялась вовсе. У этих аккаунтов не было записи с настройками, и условие, которое ждало «google» или «yandex», не срабатывало ни для одного варианта. Я добавил в Rails-модель аккаунта Google по умолчанию для такого случая. Исправление вышло через три дня.",[15,77,78],{},"В Safari после отправки страница неожиданно прокручивалась наверх, это я тоже исправил. На некоторых Android-устройствах клавиатура закрывала поле внутри задания провайдера. Полностью решить это на нашей стороне не получилось, поэтому я собрал тестовую страницу, записал видео и передал проблему в поддержку Yandex Cloud.",[10,80,82],{"id":81},"результат","Результат",[84,85,86,90,93,96],"ul",{},[87,88,89],"li",{},"2 провайдера, Google reCAPTCHA и Yandex SmartCaptcha, выбираются 1 настройкой магазина для поддерживаемых форм.",[87,91,92],{},"Капча работает в 3 поколениях оформления заказа, 2 поколениях личного кабинета, 4 семействах форм витрины и во входе владельцев магазинов.",[87,94,95],{},"Поддерживаемые формы отправляются с невидимой проверкой, без обязательного чекбокса.",[87,97,98,99,106,107,112],{},"Разработчики магазинов получили документированные API и примеры для подключения капчи к своим формам: для ",[100,101,105],"a",{"href":102,"rel":103},"https:\u002F\u002Fdocs.liquidhub.ru\u002F%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B%20%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B%20%D1%81%20%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC%D0%B8%20%D0%BC%D0%B0%D0%B3%D0%B0%D0%B7%D0%B8%D0%BD%D0%B0\u002FreCAPTCHA\u002Frecaptcha-common\u002F",[104],"nofollow","Google reCAPTCHA"," и ",[100,108,111],{"href":109,"rel":110},"https:\u002F\u002Fwww.insales.ru\u002Fcollection\u002Fprimery-raboty-s-dannymi-magazina\u002Fproduct\u002Fyandex-captcha",[104],"Yandex SmartCaptcha",".",[10,114,116],{"id":115},"ограничения","Ограничения",[15,118,119],{},"Выбор провайдера не сделал капчу обязательной везде: у каждой формы остались свои правила, когда проверка нужна. Формы, встроенные в старые темы, и кастомные виджеты со своей интеграцией нужно было обновлять вручную. Покрыты не все формы админки.",{"title":121,"searchDepth":122,"depth":122,"links":123},"",2,[124,125,126,134,135],{"id":12,"depth":122,"text":13},{"id":23,"depth":122,"text":24},{"id":30,"depth":122,"text":31,"children":127},[128,130,131,132,133],{"id":35,"depth":129,"text":36},3,{"id":42,"depth":129,"text":43},{"id":49,"depth":129,"text":50},{"id":59,"depth":129,"text":60},{"id":71,"depth":129,"text":72},{"id":81,"depth":122,"text":82},{"id":115,"depth":122,"text":116},"Платформа витрин","inSales","\u002Fimages\u002Fwork\u002Fform-protection\u002Finvisible-captcha-submit-flow.svg","Схема отправки формы: проверка полей, ожидание токена капчи и продолжение отправки только той формы, которая его запросила",null,"Невидимая капча внутри отправки форм inSales — в оформлении заказа, личном кабинете и формах магазина. Затем выбор между Google reCAPTCHA и Yandex SmartCaptcha одной настройкой магазина.","md",false,"ru",{},true,11,"\u002Fru\u002Fprojects\u002Fform-protection",[150,153,156],{"value":151,"label":152},"2","провайдера капчи, Google и Яндекс, на выбор для поддерживаемых форм магазина",{"value":154,"label":155},"3","поколения оформления заказа с капчей: 1.0, 2.0 и 3.0",{"value":157,"label":158},"4","семейства форм витрины в общей JavaScript-библиотеке","Отвечал за frontend-интеграцию, общий код капчи и выпуск",{"title":5,"description":141},"form-protection",[163,164,165,166,105,111],"JavaScript","Vue","Slim","Liquid","ru\u002Fprojects\u002Fform-protection","Октябрь 2023 – июль 2026","SL49sCgOT9k7hptfrdjj-PxdLlO9Fe9EoQjcvgE3gNY",[171,182,187,202,212,217,222,227],{"stem":172,"name":173,"date":174,"featured":122,"published":146,"mentions":175},"recommendations\u002Fandrey-stikheev","Andrey Stikheev","2026-09-08",[176,179],{"project":177,"quote":178},"product-image-editor","Among his most notable projects was a sophisticated browser-based image editor built with TypeScript and Fabric.js, now used by thousands of merchants.",{"project":180,"quote":181},"abandoned-carts","He also developed the frontend for a paid abandoned-cart product and contributed to the production migration from Vue 2 to Vue 3.",{"stem":183,"name":184,"date":185,"featured":140,"published":146,"mentions":186},"recommendations\u002Fdaniil-churakov","Daniil Churakov","2026-08-27",[],{"stem":188,"name":189,"date":190,"featured":129,"published":146,"mentions":191},"recommendations\u002Fdmitry-sadovsky","Dmitry Sadovsky","2026-08-22",[192,195,197,200],{"project":193,"quote":194},"visual-storefront","For years he was the driving force behind our visual storefront editor — a large, complex application where merchants build their online stores.",{"project":177,"quote":196},"It became the tool merchants use to design product images right inside the admin panel — the kind of component companies usually buy rather than build.",{"project":198,"quote":199},"image-editor","What impressed me most was the infographic editor he built essentially from scratch: a full canvas-based graphic editor with artboards, shapes, text styling, templates, and undo\u002Fredo history, powered by an editor core he developed himself.",{"project":180,"quote":201},"Our abandoned carts functionality — with multi-channel customer messaging, communication history, and analytics — was largely his work, from UI down to the details of how requests are cancelled and states stay in sync.",{"stem":203,"name":204,"date":205,"featured":206,"published":146,"mentions":207},"recommendations\u002Fegor-fedkin","Egor Fedkin","2026-08-31",1,[208,210],{"project":177,"quote":209},"Today, the tool is actively used by around 3,000 users.",{"project":180,"quote":211},"It has already generated approximately twice the revenue needed to cover its development costs.",{"stem":213,"name":214,"date":215,"featured":140,"published":146,"mentions":216},"recommendations\u002Femmanuel-stephen","Emmanuel Stephen","2026-10-11",[],{"stem":218,"name":219,"date":220,"featured":140,"published":146,"mentions":221},"recommendations\u002Fevgeny-lonshakov","Евгений Лоншаков","2026-09-21",[],{"stem":223,"name":224,"date":225,"featured":140,"published":146,"mentions":226},"recommendations\u002Froman-gorbachev","Роман Горбачев","2026-09-17",[],{"stem":228,"name":229,"date":230,"featured":140,"published":146,"mentions":231},"recommendations\u002Fvladimir-bedarev","Bedarev Vladimir","2026-09-16",[],1793195987339]