Примеры кода написаны на React, TypeScript и Node.js.
Даже в 2022 году, спустя более десяти лет с момента изобретения reCAPTCHA, я считаю, что понять, как Google reCAPTCHA работает и интегрируется с веб-приложением, по-прежнему не так просто, если вы впервые смотрите на него, благодаря минимальному количеству официальных документов.
После долгих чтений, копаний и проб и ошибок я думаю, что наконец понял это, но я также верю, что для новичков должен быть гораздо более простой способ разобраться, который будет содержать четкие диаграммы и простые примеры кода.
Вот почему я написал эту статью — чтобы сделать шаг вперед для тех, кто хочет понять Google reCAPTCHA проще и быстрее.
Основы
Чтобы обсудить Google reCAPTCHA, нам нужно начать с более простой концепции — CAPTCHA.
CAPTCHAрасшифровывается как «Полностью автоматизированный публичный тест Тьюринга для определения различий между компьютерами и людьми» [1], который является широко используемым методом предотвращения ботов. от выполнения таких действий, как регистрация учетной записи.
Например, вы, вероятно, уже видели что-то подобное ниже при регистрации или входе в систему на многих веб-сайтах, где вас просят ввести символы, распознанные на изображении.
Тем не менее, принуждение пользователей к чтению и вводу символов является трением и прерыванием, и умные боты могут легко идентифицировать эти искаженные буквы, а затем пройти тест.
Таким образом, для борьбы с ботами вводятся более продвинутые методы тестирования, а наиболее популярным решением является Google reCAPTCHA.
Разбираться в разных версиях Google reCAPTCHA
Вступив в мир Google reCAPTCHA, вы сразу же столкнетесь с проблемой выбора из дерева доступных вариантов [2]:
- reCAPTCHA v2 (флажок «Я не робот»)
- reCAPTCHA v2 (невидимый значок reCAPTCHA)
- reCAPTCHA v3
К сожалению, официальные документы имеют только краткое введение, оставляя радость глубокого погружения нам, желающим узнать больше.
reCAPTCHA v2 (флажок «Я не робот»)
Прежде всего, давайте предположим, что у нас есть такой экран регистрации:
Мы ожидаем, что поток будет:
«Вызов выбора изображения» — это всплывающее окно, как показано ниже:
Ключом к пониманию того, «как» и «почему» работает поток, является токен за кулисами:
- Когда вы нажимаете «Я не бот», reCaptcha проверяет, не являетесь ли вы ботом.
- Если reCAPTCHA посчитает, что вы вряд ли бот, то выдаст вам токен.
- Если reCAPTCHA решит, что вы можете быть ботом, появится всплывающее окно с викториной по выбору изображения, и вы сможете получить токен только после того, как успешно ответите на викторину.
- Когда веб-интерфейс отправляет окончательный запрос «регистрации» на сервер API, он не только содержит «имя пользователя» в полезной нагрузке, но также включает «токен», выданный reCAPTCHA.
- Когда сервер API получает запрос, он проверит токен, обратившись к серверу reCAPTCHA, и предотвратит регистрацию пользователя, если токен недействителен.
Таким образом, мы можем представить поток с помощью следующих диаграмм последовательности:
При отсутствии вызова изображения (источник диаграммы):
Когда есть вызов изображения (источник диаграммы):
Пример кода: интерфейс
Давайте посмотрим на пример компонента React для деталей реализации.
Прежде всего, компонент отобразит форму с вводом имени пользователя, флажком reCAPTCHA, кнопкой регистрации и сообщением об ошибке.
<form className="Form" data-testid="FormWithCheckbox" data-registration-result={registrationResult}> <div> <label> <span>username: </span> <input type="text" name="username" value={username} onChange={handleUsernameChange} /> </label> </div> <ReCAPTCHA sitekey={SITE_KEY} onChange={handleRecaptchaChange} /> <button type="button" onClick={handleClickRegister}> register </button> {errorMessage && <div className="Error">{errorMessage}</div>} </form>
Здесь стоит упомянуть, что мы используем библиотеку — react-google-recaptcha для удобной настройки и рендеринга reCAPTCHA.
Затем мы сохраняем состояния форм для имени пользователя и токена и обновляем их с помощью обратных вызовов (используемых в JSX).
const [username, setUsername] = React.useState(""); const [recaptchaToken, setRecaptchaToken] = React.useState<string | null>(null); const handleRecaptchaChange = React.useCallback((value: string | null) => { console.log("FormWithCheckbox::handleRecaptchaChange > value: ", value); setRecaptchaToken(value); }, []); const handleUsernameChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => { const value = trim(event.target.value); setUsername(value); }, []);
Наконец, когда пользователь нажимает «зарегистрироваться», мы отправляем запрос API с именем пользователя и токеном.
const [registrationResult, setRegistrationResult] = React.useState(""); const [errorMessage, setErrorMessage] = React.useState(""); const handleClickRegister = React.useCallback(async () => { setErrorMessage(""); if (!recaptchaToken) { alert("Please click reCAPTCHA checkbox!"); return; } try { const response = await axios.post("/api/user/registration", { username, recaptchaToken, recaptchaVersion: "V2_CHECKBOX", }); const { result } = response.data; console.log("FormWithCheckbox::handleClickRegister > result: ", result); setRegistrationResult(trim(result)); alert("Register success"); } catch (e: any) { const response = e.response; const { result, error } = response.data; setRegistrationResult(trim(result)); setErrorMessage(trim(error)); } }, [recaptchaToken, username]);
Пример кода: бэкенд
Код node.js для обработки запроса API очень прост:
- Подтвердить ввод пользователя
- Проверить токен reCAPTCHA
- Выполнить основное действие (например, зарегистрироваться)
- Возвращаемый результат
app.post("/api/user/registration", async (req, res) => { const recaptchaVersion = _.trim(_.get(req.body, "recaptchaVersion")); const username = _.trim(_.get(req.body, "username")); const token = _.trim(_.get(req.body, "recaptchaToken")); try { validateUsername(username); const secret = getSecretByRecaptchaVersion(recaptchaVersion); await verifyRecaptchaToken({ token, secret }); // ... Register ... res.status(201).json({ result: "SUCCESS", username }); } catch (e) { console.error(e); res.status(400).json({ result: "FAIL", error: _.get(e, "message") ? _.get(e, "message") : JSON.stringify(e), }); } });
…и вот код для проверки токена reCAPTCHA:
type VerifyRecaptchaTokenArgs = { secret: string; token: string; }; const verifyRecaptchaToken = async (args: VerifyRecaptchaTokenArgs) => { const { secret, token } = args; if (!token || !secret) { throw new Error("reCAPTCHA secret or token is invalid"); } const response = await axios.post( "https://www.google.com/recaptcha/api/siteverify", undefined, { params: { secret, response: token }, } ); console.log("reCAPTCHA siteverify result: ", response.data); if (!response.data.success) { throw new Error("reCAPTCHA token is invalid"); } };
Полный код можно найти на Github:
reCAPTCHA v2 (невидимый значок reCAPTCHA)
При использовании этой опции весь процесс идентичен варианту с флажком, за исключением того, что пользователю не нужно будет отмечать «Я не бот» — он неявно ставится, когда пользователь нажимает кнопку основного действия (например, «зарегистрироваться»). кнопка).
Таким образом, когда нет задачи изображения, диаграмма последовательности может быть построена, как показано ниже (источник диаграммы):
…и это при вызове выбора изображения (источник диаграммы):
Пример кода
Хотя внутренний код в основном идентичен предыдущему примеру с флажком, внешний интерфейс немного отличается: мы запускаем проверку reCAPTCHA, когда пользователь нажимает «зарегистрироваться», а не нажимает на флажок.
reCAPTCHA v3
Этот вариант сильно отличается от двух предыдущих — он не использует всплывающее окно «выбор изображения», чтобы проверить, является ли пользователь ботом или нет.
Вероятно, мы могли бы даже сказать, что CAPTCHA вообще не существует: reCAPTCHA v3 утверждает, что имеет возможность наблюдать за взаимодействием пользователей с сайтом и вычисляет оценку за действие пользователя, тогда наш сервер может использовать настраиваемый порог, чтобы решить, действие должно быть разрешено или заблокировано.
С диаграммой (исходником) было бы проще разобраться:
Очень важно понимать, что при использовании reCAPTCHA v3 у пользователя нет такой возможности доказать, что он/она не является ботом. Когда API получает результат проверки токена reCAPTCHA, мы можем либо разрешить пользователю продолжить, либо дать пользователю жесткую остановку с ошибкой на основе «оценки».
Также стоит отметить, что проверка на «оценку» может быть разной для разных действий пользователя. Например, у нас может быть разный порог для «регистрации» и «логина».
Пример кода
Примечание: мы используем библиотеку под названием react-google-recaptcha-v3, чтобы упростить интеграцию reCAPTCHA в приложение React.
Прежде всего, нам нужно инициализировать reCAPTCHA как можно раньше:
root.render( <React.StrictMode> <GoogleReCaptchaProvider reCaptchaKey={SITE_KEY}> <App /> </GoogleReCaptchaProvider> </React.StrictMode> );
Затем нам нужно получить токен и отправить запрос, когда пользователь нажмет «зарегистрироваться»:
const App = () => { const { executeRecaptcha } = useGoogleReCaptcha(); const handleClickRegister = React.useCallback(async () => { if (!executeRecaptcha) { console.log("Execute recaptcha not yet available"); return; } const recaptchaToken = await executeRecaptcha("register"); // TODO: send API request and get result }, [executeRecaptcha, username]); return ( <div className="App"> {/* ... */} <button type="button" onClick={handleClickRegister}> register </button> {/* ... */} </div> ); };
Возможно, вы уже заметили, что при получении токена мы также сообщаем reCAPTCHA action
, что означает «зарегистрироваться».
Наконец, нам нужно проверить токен с помощью «action» и «score» в бэкенде:
const verifyRecaptchaToken = async (args: VerifyRecaptchaTokenArgs) => { // ... Get token verify result ... const score = _.toNumber(_.get(response.data, "score")); const action = _.toString(_.get(response.data, "action")); if (action === "register" && score < 0.5) { throw new Error("Bot detected!"); } };
Как показано в приведенном выше коде, мы используем 0.5
в качестве порога для действия «регистрация». То есть, если оценка равна или выше 0,5, мы разрешаем пользователю зарегистрироваться; если оценка ниже 0,5, мы выдаем ошибку и останавливаем регистрацию пользователя.
Материал
Вы можете найти полные и работоспособные примеры кода для всех трех вариантов (флажок V2, невидимый V2 и V3) в репозитории на моем github:
Примечание: ключи для reCAPTCHA включены и жестко запрограммированы в репозитории для удобства. Я бы порекомендовал зарегистрировать собственную учетную запись и получить собственные ключи, если вы хотите узнать больше о reCAPTCHA.
Дальнейшее обсуждение
Хотя reCAPTCHA является наиболее популярным выбором, у вас могут быть некоторые опасения по поводу обязательства конфиденциальности, и эти опасения абсолютно обоснованы. Например, вы можете прочитать эту статью[3], чтобы понять, как привести ваше приложение в соответствие с GDPR при использовании reCAPTCHA.
В качестве альтернативы hCaptcha претендует на то, чтобы заменить Google reCAPTCHA, но более дружелюбен к различным политикам конфиденциальности. Так что, возможно, стоит взглянуть, если вас беспокоят политика и правила конфиденциальности.
Рекомендации
- [1] https://en.wikipedia.org/wiki/CAPTCHA
- [2] https://developers.google.com/recaptcha/docs/versions
- [3] https://measuredcollective.com/gdpr-recaptcha-how-to-stay-compliant-with-gdpr/
Больше контента на PlainEnglish.io.
Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord.
Хотите масштабировать свой технический стартап с помощью контента? Посмотрите Цирк.
Мы предлагаем бесплатные консультации экспертов и индивидуальные решения, которые помогут вам повысить осведомленность о вашем технологическом продукте или услуге и принять их.