Взлом 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Информация о клиенте (варьируется, значение - "webapp" через веб-интерфейс Google Translate; влияет на формат возврата и ограничение скорости)
формат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

Здесь Deobfuscater оставил немного мусора; После того, как мы заменили 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-запросы требуют заголовка длины содержимого ». Поэтому рекомендуется включить этот заголовок (который автоматически устанавливается в качестве временного заголовка в 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 .

Назад