Злом 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Інформація про клієнта (змінюється, значення "webapp" через веб-інтерфейс Google Translate; впливає на формат повернення та обмеження швидкості)
формат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

Тут 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 вимагають заголовка довжини вмісту ". Тому доцільно включити цей заголовок (який автоматично встановлюється як тимчасовий заголовок у Поштовику).

Формат повернення перекладених рядків є незвичним, коли в одному запиті є кілька речень. Окремі речення укладені тегами 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 .

Назад