Взлом Google Translate API

Google предлагает API перевода Google со структурой затрат на основе использования как часть своего Google Cloud. Существует также недокументированный API, который можно использовать без ключа , но который отказывается работать после нескольких запросов. При использовании функции перевода веб-сайтов в Google Chrome заметно, что страницы можно переводить в очень хорошем качестве без каких-либо заметных ограничений.


Судя по всему, здесь уже используется продвинутая модель nmt . Но какой API Google Chrome использует внутри себя для перевода контента, и можете ли вы также получить доступ к этому API напрямую — даже на стороне сервера? Для анализа сетевого трафика мы рекомендуем такие инструменты, как Wireshark или Telerik Fiddler , которые также могут анализировать зашифрованный трафик. Но Chrome даже бесплатно доставляет запросы, которые он отправляет при переводе страниц: их легко просмотреть через Chrome DevTools.:

Если вы выполняете перевод, а затем перехватываете важный запрос POST к https://translate.googleapis.com с помощью «Копировать> Копировать как cURL (bash)» и выполняете его в таком инструменте, как Postman , например, вы можете отправить запрос снова без проблем.:

Смысл параметров URL-адреса также в основном очевиден.:

КлючПример значенияИмея в виду
анно3Режим аннотации (влияет на формат возврата)
клиентte_libИнформация о клиенте (различается; в веб-интерфейсе Google Translate значение равно "webapp"; влияет на формат возвращаемого значения и ограничение скорости запросов).
форматhtmlФормат строки (важно для перевода HTML-тегов)
v1.0Номер версии Google Translate
ключAIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwКлюч API (см. Ниже)
logldvTE_20200210_00Версия протокола
слдеЯзык источника
tlenЯзык перевода
зрнмтML модель
tc1неизвестно
SR1неизвестно
тк709408.812158Токен (см. Ниже)
Мода1неизвестно

Также установлены некоторые заголовки запросов, но их можно игнорировать. После ручного снятия выделения со всех заголовков, включая заголовки пользовательского агента , при вводе специальных символов обнаруживается проблема кодирования (здесь при переводе " Hello World "):

Если вы повторно активируете пользовательский агент (что обычно не причиняет никакого вреда), API доставит символы в кодировке UTF-8.:

Достигли ли мы теперь своей цели и располагаем всей необходимой информацией для использования этого API вне Google Chrome? Однако, если вы измените строку для перевода (поле данных q POST-запроса), например, с "Hello World" на "Hello World ! ", вы получите сообщение об ошибке.:

Теперь мы выполняем еще один перевод этой измененной строки в Google Chrome, используя функцию перевода веб-сайтов, и обнаруживаем, что, помимо параметра q , изменился и параметр tk (все остальные параметры остались прежними).:

Судя по всему, это токен, который зависит от строки, структуру которой непросто увидеть. При запуске перевода сайта загружаются следующие файлы:

  • 1 файл CSS: translateelement.css
  • 4 графика: translate_24dp.png (2x), gen204 (2x)
  • 2 файла JS: main_de.js , element_main.js

Два файла JavaScript обфусцированы и уменьшены. Такие инструменты, как JS Nice и de4js , теперь помогают нам сделать эти файлы более читабельными. Чтобы отлаживать их в реальном времени, мы рекомендуем запрос расширения Chrome , который туннелирует удаленные файлы локально на лету.:

Теперь мы можем отладить код (сначала нужно активировать CORS на локальном сервере). Соответствующий раздел кода для создания токена кажется скрытым в этом разделе файла element_main.js.:

b7739bf50b2edcf636c43a8f8910def9

Здесь текст хешируется с помощью битовых сдвигов . Но, к сожалению, нам все еще не хватает одной части головоломки: в дополнение к аргументу a (который является текстом, который нужно перевести), другой аргумент b передается функции Bp () - своего рода начальное число, которое, кажется, время от времени меняется и которое также включает перетекает в хеширование. Но откуда он? Если мы перейдем к вызову функции Bp () , мы найдем следующий фрагмент кода:

b7739bf50b2edcf636c43a8f8910def9

Функция Hq заранее объявляется следующим образом:

b7739bf50b2edcf636c43a8f8910def9

Деобфускатор оставил здесь какой-то мусор; после того, как мы заменили String.fromCharCode('...') соответствующими строками, удалили устаревший a() и собрали воедино вызовы функций [c(), c()] , мы получим:

b7739bf50b2edcf636c43a8f8910def9

Или даже проще:

b7739bf50b2edcf636c43a8f8910def9

Функция yq ранее определялась как:

b7739bf50b2edcf636c43a8f8910def9

Таким образом, исходное значение находится в глобальном объекте google.translate._const._ctkk , который доступен во время выполнения. Но где оно размещено? По крайней мере, он также доступен вначале в другом, ранее загруженном JS-файле main_de.js . В начале добавляем следующее:

b7739bf50b2edcf636c43a8f8910def9

В консоли мы фактически получаем текущее семя:

Это оставляет сам Google Chrome, который, по-видимому, предоставляет начальное число, в качестве последнего варианта. К счастью, его исходный код (Chromium, включая компонент Translate) является открытым и поэтому общедоступным. Вытаскиваем репозиторий локально и находим вызов функции TranslateScript :: GetTranslateScriptURL в файле translate_script.cc в папке components / translate / core / browser:

b7739bf50b2edcf636c43a8f8910def9

Переменная с URL-адресом жестко определена в том же файле:

b7739bf50b2edcf636c43a8f8910def9

Если мы теперь рассмотрим файл element.js более внимательно (после дальнейшей деобфускации), мы обнаружим жестко установленную запись c._ctkk — объект google.translate также установлен соответствующим образом и запускается загрузка всех соответствующих ресурсов (которые мы уже обнаружили ранее).:

b7739bf50b2edcf636c43a8f8910def9

Теперь остается рассмотреть ключ параметра (со значением AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw). Похоже, это общий ключ API браузера (который также можно найти в некоторых результатах Google ). Он установлен в Chromium в файле translate_url_util.cc в папке components / translate / core / browser.:

b7739bf50b2edcf636c43a8f8910def9

Ключ создается в google_apis / google_api_keys.cc из фиктивного значения:

b7739bf50b2edcf636c43a8f8910def9

Однако тестирование показывает, что вызовы API работают так же хорошо и без этого ключевого параметра. Эксперименты с API теперь возвращают код состояния 200 при успешных вызовах. Если достигается лимит, возвращается код состояния 411 с сообщением « POST-запросы требуют заголовка Content-length ». Поэтому рекомендуется также включать этот заголовок (который автоматически устанавливается как временный заголовок в Postman).

Формат возврата переведенных строк необычен, когда в одном запросе содержится несколько предложений. Отдельные предложения заключены в теги i- / b-HTML.:

Кроме того, Google Chrome не отправляет весь HTML-код в API, но сохраняет значения атрибутов, такие как href, в запросе (и вместо этого устанавливает индексы, чтобы теги могли позже быть назначены на стороне клиента):

Если вы измените значение клиента ключа POST из te_lib (Google Chrome) в webapp ( веб-сайт Google Translation ) вы получите окончательную переведенную строку:

Проблема в том, что у вас гораздо больше шансов столкнуться с ограничением скорости, чем через te_lib (для сравнения: с webapp это достигается после 40 000 символов, с te_lib ограничения скорости нет). Поэтому нам нужно внимательнее взглянуть на то, как Chrome анализирует результат. Мы найдем его здесь, в element_main.js:

b7739bf50b2edcf636c43a8f8910def9

Если вы отправляете весь HTML-код в API, он оставляет атрибуты в переведенном ответе. Поэтому нам не нужно имитировать все поведение синтаксического анализа, а только извлекать последнюю переведенную строку из ответа. Для этого мы создаем небольшой синтаксический анализатор тегов HTML, который отбрасывает самые внешние теги <i>, включая их содержимое, и удаляет самые внешние теги <b>. Обладая этими знаниями (после установки зависимостей с помощью composer require fzaninotto / faker vielhuber / stringhelper ) мы можем теперь создать серверную версию API перевода.:

b7739bf50b2edcf636c43a8f8910def9

Ниже приведены результаты первоначального теста, проведенного на пяти разных системах с разной пропускной способностью и IP-адресами.:

ПерсонажСимволов на запросПродолжительностьЧастота ошибокСтоимость через официальный API
13.064.662~25003: 36: 17ч0%237,78 €
24.530.510~25011: 09: 13ч0%446,46 €
49.060.211~25020: 39: 10 ч0%892,90 €
99.074.487~100061: 24: 37ч0%1803,16 €
99.072.896~100062: 22: 20ч0%1803,13 €
Σ284.802.766~ Ø550Σ159: 11: 37ч0%€5183,41

Примечание: это сообщение в блоге, включающее все сценарии, было написано только для тестовых целей. Не используйте сценарии для продуктивного использования, а не работать с официальным API Google Translation .

Назад