Злом API перекладу Google

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)" і виконайте його в такому інструменті, як Поштовець , наприклад, ви можете відправити запит знову без проблем:

Значення параметрів URL-адреси також здебільшого очевидне.:

КлючПриклад значенняЗначення
ано3Режим анотацій (впливає на формат повернення)
клієнтte_libІнформація про клієнта (варіюється; через веб-інтерфейс Google Translate значення — «webapp»; впливає на формат повернення та обмеження швидкості)
форматhtmlФормат рядка (важливий для перекладу тегів HTML)
v1.0Номер версії Google Translate
ключAIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwКлюч API (див. Нижче)
logldvTE_20200210_00Версія протоколу
слдеМова-джерело
tlenМова перекладу
spnmtМодель ML
tc1невідомо
сер1невідомо
tk709408.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 Requestly, яке на ходу тунелює локальні віддалені файли:

Тепер ми можемо налагодити код ( 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 requests require a Content-length header ». Тому рекомендується також включити цей заголовок (який автоматично встановлюється як тимчасовий заголовок у Postman).

Формат повернення перекладених рядків є незвичним, коли в одному запиті є кілька речень. Окремі речення укладені тегами i- / b-HTML:

Крім того, Google Chrome не надсилає повний HTML до API, але зберігає значення атрибутів, такі як href, у запиті (і замість цього встановлює індекси, щоб теги можна було потім призначити на стороні клієнта):

Якщо ви змінили значення клієнта ключа POST з te_lib (Google Chrome) на webapp ( веб-сайт Google Translate ) ви отримуєте остаточний перекладений рядок:

Проблема полягає в тому, що ви набагато більше шансів нарватися на обмеження швидкості , ніж через te_lib (для порівняння: з веб - додаток це досягається після 40000 символів, з te_lib немає обмеження швидкості). Тому нам слід уважніше розглянути, як Chrome аналізує результат. Ми знайдемо його тут у елементі_main.js:

b7739bf50b2edcf636c43a8f8910def9

Якщо ви надсилаєте весь HTML-код до API, він залишає атрибути в перекладеній відповіді. Тому нам не потрібно повністю імітувати поведінку аналізу, а лише витягувати остаточний перекладений рядок із відповіді. Для цього ми створюємо невеликий аналізатор тегів HTML, який відкидає найвіддаленіші теги <i>, включаючи їх вміст, і видаляє крайні теги <b>. З цими знаннями ми можемо тепер (після встановлення залежностей за допомогою composer вимагає 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 .

Назад