Очень важный дисклеймер: обмануть капчу невозможно.
Если вы уже столкнулись с этой проблемой, и читаете эту статью, пытаясь нагуглить рецепт панацеи, то знайте, что его не существует. Тем более, в вашей голове уже скорее всего возникли инновационные мысли о том, чтобы сымитировать реалистичное поведение пользователя с помощью WebDriver, путём рандомного mouse overing'а элементов, кликов по инпутам, и бережно расставленных Thread.sleep(). Абсолютно точно известно, что этот подход работать не будет, не тратьте свое время попусту.
![image](https://www.scienceabc.com/wp-content/uploads/2016/07/Captcha-meme.jpg)
Получается, выхода нет?
Не все так пессимистично. Иногда достаточно постараться дать себе наиболее точный ответ на вопрос «Какая задача передо мной стоит?» и посмотреть на ситуацию шире. В большинстве случаев, вы поймете, что ваша цель не обмануть капчу, а обойти её, чтобы протестировать функционал, спрятанный за ней. На примере своего кейса, я поделюсь с вами найденными мною вариантами решения поставленной задачи.
Контекст: мы интегрировали часть своего продукта внутрь стороннего сервиса, и хотели мониторить, все ли в порядке на их стороне, т.к. они не занимаются покрытием third-party частей своей платформы. Чтобы получить доступ к нашему функционалу, сперва необходимо было залогиниться. Тут-то я и встретился с капчей лицом к лицу. Далее привожу все перепробованные мною варианты обхода данной проблемы.
Нерабочие
Залогиниться через Google или Facebook
Помимо классической аутентификации, присутствовали каноничные «Login with Google / Facebook». Само собой, там точно также присутствовали свои «капчи», поэтому этот вариант не помог решить проблему.
Имитация поведения пользователя
Да, я тоже это пробовал. Было забавно, но чересчур наивно.
Рабочие
Chrome / Firefox Profiles
Поговорим о первом «живом» варианте. В драйверах для этих браузеров (chromedriver / geckodriver) реализована возможность загружаться под заранее заготовленным User Profile. Он хранит в себе все сохраненные пароли, куки, сессии, и даже историю браузера и закладки. Т.е. таким образом мы попросту пропускали абсолютно неважный для нашей задачи шаг логина, и таким образом попадали сразу на страницу с объектом тестирования. Реализуется это следующим образом:
- Создаем «чистый» профиль браузера
- Вручную вводим капчу и логинимся на нужный ресурс
- Копируем необходимый профиль в наш проект (HOWTO для Firefox и Chrome)
После чего, нам необходимо сказать драйверу, что грузиться он должен именно с указанного профиля:
Firefox:
// Инициализируем профиль
FirefoxProfile profile = new FirefoxProfile(new File("/путь/к/вашему/профилю"));
// Указываем профиль в передаваемых опциях
FirefoxOptions options = new FirefoxOptions();
options.setProfile(profile);
// Создаем браузер
WebDriver driver = new FirefoxDriver(options);
Chrome:
// Указываем профиль в передаваемых опциях
ChromeOptions options = new ChromeOptions();
options.addArgument("--user-data-dir=/путь/к/папке/с/профилями");
options.addArgument("--profile-directory=Название_папки_с_нужным_профилем");
// Создаем браузер
WebDriver driver = new ChromeDriver(options);
Этот подход хорошо показал себя при тестировании на локальной машине с установленным браузером и обычными gecko-/cromedriver’ами, но возникли проблемы при запуске на Jenkins. Мы поднимаем Selenium хаб и ноды внутри Kubernetes кластера, поэтому мы столкнулись с неприятностями в виде слишком долгого по времени маунта директории внутрь контейнера (чистый профиль в среднем весит около 25 MB, что немало), а так же некоторых проблем с CRUD правами браузера, который не мог вносить изменения в профайл в рантайме, и падал с “unknown error: failed to write prefs file” эксепшеном. Ко всему прочему, апдейтить профайл после достижения куками и сессиями своих Expiration Dates достаточно неудобно, да и не хотелось держать в проекте огромную папку с внутренностями профиля, поэтому в конечном итоге окончательным был выбран следующий вариант.
Cookies
“А ларчик просто открывался” — именно так можно было охарактеризовать ситуацию, после того, как мы просто добавили полученные вручную куки в драйвер. Алгоритм действий максимально прост и не зависит от выбранного браузера:
- Логинимся вручную
- Через Network смотрим Request Headers -> Cookie которые посылает наш браузер
Добавляем их в наши тесты следующим образом:
// Создаем cookie
private static final Cookie COOKIE = new Cookie("имя", "содержимое", "домен", "путь", new Date("дата"));
// Создаем браузер
WebDriver driver = new ChromeDriver(options);
// Добавляем cookie в браузер
driver.manage().addCookie(COOKIE);
Очевидный минус этого подхода — необходимость вручную менять куки после истечения их срока валидности. Но, в виду того что на тестируемой платформе этот срок составляет 3 месяца — мы и выбрали это решение.
А если мне не нужно логиниться?
А как же ситуация, когда речь идет не о авторизации и сессиях, а о совершении какого-либо одноразового действия (e.g. оформление заказа из корзины, регистрация нового пользователя и т.п.)? Здесь ситуация еще хуже. Два варианта которые я смог обнаружить, это:
- Договориться с вашими разработчиками о предоставлении вам некого workaround'а. Google предоставляет такую возможность, но помните, что вы осознанно делаете небольшую дыру в security.
- Воспользоваться сторонними платными сервисами, которые принимают с вашей стороны скриншот капчи, пытаются его декодировать, и отправляют вам расшифрованное значение. Сам я такой способ не пробовал и полностью рекомендовать его не могу.
Подведем итоги
Как вы могли убедиться — безвыходных ситуаций не бывает. Однако, будет глупо отрицать, что у абсолютно всех вышеперечисленных вариантов есть свои, достаточно весомые, минусы, так что выбор остается за вами.
Спасибо за внимание.
P.S. Если вы знаете еще какие-либо работающие в реальной жизни решения — пожалуйста, опишите их в комментариях, будет очень интересно почитать.
Комментарии (18)
dididididi
28.02.2019 10:03Не сталкивался с капчой ни разу, а что отключить ее на тестовой среде так сложно?
Kovylin77 Автор
28.02.2019 12:43Думаю не сложно. Но тут играли роль два фактора:
— Это был сторонний сервис, на который мы не имеем большого влияния
— Это был production environment, на котором ее точно отключать не нужно
tuxi
28.02.2019 10:15А на Яндекс.Поиске не пробовали тестировать? Я имею в виду ситуацию, когда на каком-нибудь очередном запросе вылезает капча «нам показалось тут что вы...»
Teomit
28.02.2019 11:34Очень важный дисклеймер: обмануть капчу невозможно.
Ну я не был бы так категоричен:
Статья 1
Статья 2Kovylin77 Автор
28.02.2019 12:44К сожалению (или к счастью), команда ReCaptcha очень быстро реагирует на подобные найденные уязвимости. Но спасибо за ссылки, будет интересно почитать
savkk
01.03.2019 11:48Честно, так и не понял о чем статья. О там как пользоваться куками в Selenium? Ну не знаю…
Если есть возможно, то лучше мониторить изменения на стороннем сервисе через предоставляемое ими API, может есть такая возможность?
Вообще не понимаю, зачем заходить туда Selenium'ом, таким образом подвергать опасности и без того хрупкие UI-тесты.
В случае необходимости периодически руками проверять UI.
Да и вообще тестить сторонние сервисы, да еще и на проде, это мне кажется прям совсем не правильно.Kovylin77 Автор
01.03.2019 12:52— Открытого API нет
— Немного не понял, каким образом мы «подвергаем опасности хрупкие UI-тесты»? :)
— Мы тестим не сторонний сервис, а наше приложение, интегрированное в него. Именно поэтому мы позволили себе обойти шаг логина, т.к. это как раз тестирование стороннего сервиса, в котором мы не заинтересованы
polarnik
03.03.2019 10:05Здравствуйте, Михаил. Хорошая тема.
В тестировании производительности использую более простые на мой взгляд способы.
Шаг 1. I'd like to run automated tests with reCAPTCHA. What should I do?
Site key: 6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
Эти настройки указываются в конфигурационном файле сервера приложений.
Secret key: 6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
Шаг 2. Настройка Fiddler и работы приложений через прокси-сервер. Так как сервер приложений всё равно будет отправлять запросы в Google, а Google для такой отладочной связки Site key + Secret key будет всегда говорить — ok. Можно автоматизировать процесс, сделать так чтобы сервер приложений работал с Google через прокси-сервер. А в прокси-сервере (использую Fidder) настроить автоответ на запрос.
2.1. Сохранить оригинальный ответ от Google ReCapcha.
2.2. Используя auto response в Fiddler сделать так, чтобы на все запросы к Google ReCapcha был фиксированный положительный ответ.
В ответе будет сказано, что результат проверки — ok. Но будет сказано, что время ответа было в прошлом. Если сервер приложений валидирует не только ответ true/false, но и время. То автоответ не сработает. Но, обычно, сервер приложений время не валидирует, что позволяет сделать замкнутую систему.
Таким образом, получаю полностью автономную систему. Которая не обращается в Интернет. И на которую можно подавать высокую нагрузку. Проверял на интенсивности до 50 сценариев в сек.Kovylin77 Автор
03.03.2019 14:59Очень крутое решение!
Спасибо, обязательно попробую, если предоставится такая возможность :)
Noiwex
Есть сервисы, которые за вас решают рекапчу. Вы им site secret и challenge id, а они вам спустя какое-то время код ответа.
Mnemonik
Если вы про то как просто решить ими проблему автоматического тестирования, то они платные. Так себе идея если это для тестов, как в статье.
Если вы про то как легко и просто обойти капчу, вон какой есть классный способ и капча не работает, то вполне достаточно реализовать капчу так, как рекомендует гугл, проверяя в его ответе не только success/failure, но и другие параметры которые он возвращает.
Капча — работает. Сервисы эти эффективны только против небрежной реализации.
Akuma
Они не настолько дорогие. По мне так проще заплатить условный доллар в месяц, чем тратить уйму времени на решение этой же задачи самому.
Kovylin77 Автор
Зависит от количества ваших тестов и частоты их прогона. Используя самый популярный, на выходе получается дешево $1.39 за 1000 решенных капч. Плюс, к тому же все они дают цифру в ~90% вероятности успеха решения. Т.е. каждый десятый тест потенциально будет flaky, что не есть хорошо
Akuma
Если вы в тестах гоняете рекаптчу, то, скорее всего, это вам очень и очень нужно, а значит вы потенциально не боитесь расходов.
На своем примере за февраль: $28 за 36000 каптч. Там не только рекаптча, но и ставка у меня стоит максимально высокая, чтобы повысить скорость.
Это около 1000 тестов в сутки. Если у вас правда столько всего, вы не заметите расходов в 30 баксов.
Kovylin77 Автор
Хм, звучит действительно неплохо, спасибо
А какой процент неверно решенных капч?
Akuma
Не знаю где посмотреть именно процент.
На основании данных сервиса (Анти-каптча, если что) около 250 ошибок (вроде бы за все время), но по ощущениям их больше.
У меня не тесты гоняются, а сервис используется на двух моих сайтах и конкретно по рекаптче я делал переотправку в случае ошибки, т.к. «правильное» решение гугл иногда не принимает.
Ну и «втупую» рекаптча может решаться по две минуты. Если вам нужно быстрее, там есть способ это ускорить.
Дополнию, что только рекапча будет стоить дороже, чем у меня. Но, блин, зачем вам столько тестов с ней гонять? :)