Google Translation API Hacking

Ca parte a Google Cloud, Google oferă API-ul Traducere Google cu o structură de costuri bazată pe utilizare. Există, de asemenea, un API nedocumentat care poate fi utilizat fără cheie , dar care refuză să funcționeze după doar câteva cereri. Atunci când utilizați funcția de traducere a site - ului web Google Chrome, se remarcă faptul că paginile pot fi traduse în calitate foarte bună, fără o limitare vizibilă.


Se pare că modelul avansat nmt este deja utilizat aici. Dar ce API folosește Google Chrome intern pentru a traduce conținutul și poate fi adresat și acest API direct - chiar și pe partea serverului? Pentru a analiza traficul de rețea, se recomandă instrumente precum Wireshark sau Telerik Fiddler , care pot analiza și traficul criptat. Dar Chrome oferă chiar și cererile pe care le trimite gratuit pentru traducerea paginii: pot fi vizualizate cu ușurință folosind Chrome DevTools:

Dacă efectuați o traducere, prindeți cererea POST crucială pentru https://translate.googleapis.com prin „Copiere> Copiere ca cURL (bash)” și executați-o într-un instrument precum Postman , de exemplu, puteți trimite din nou solicitarea fără probleme:

Semnificația parametrilor URL este, de asemenea, în mare măsură evidentă:

CheieExemplu de valoareSens
anno3Mod adnotare (afectează formatul de returnare)
clientte_libInformații despre clienți (variază, valoarea este „webapp” prin interfața web a Google Translate; are un efect asupra formatului de returnare și limitarea ratei)
formathtmlFormat șir (important pentru traducerea etichetelor HTML)
v1.0Numărul versiunii Google Translate
cheieAIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwCheie API (vezi mai jos)
logldvTE_20200210_00Versiunea protocolului
sldeLimba-sursă
tlroLimbă țintă
spnmtModelul ML
tc1necunoscut
sr1necunoscut
tk709408.812158Indicativ (vezi mai jos)
Modă1necunoscut

Unele antete de solicitare sunt, de asemenea, setate - dar acestea pot fi ignorate în mare parte. După deselectarea manuală a tuturor antetelor, inclusiv a celor de la agentul utilizator , se descoperă o problemă de codificare la introducerea caracterelor speciale (aici când se traduce „ Hello World ”):

Dacă reactivați agentul utilizator (care, în general, nu dăunează), API furnizează caractere codate UTF-8:

Suntem deja acolo și avem toate informațiile pentru a utiliza acest API în afara Google Chrome? Dacă schimbați șirul de tradus (câmpul de date q al cererii POST) din, de exemplu, „Hello world” în „Hello world ! „, Primim un mesaj de eroare:

Acum îl traducem din nou pe Google Chrome folosind funcția de traducere a site-ului și constatăm că, pe lângă parametrul q , parametrul tk s-a schimbat și (toți ceilalți parametri au rămas aceiași):

Evident, este un simbol care depinde de șir, a cărui structură nu este ușor de văzut. Când porniți traducerea site-ului, sunt încărcate următoarele fișiere:

  • 1 fișier CSS: translateelement.css
  • 4 grafice: translate_24dp.png (2x), gen204 (2x)
  • 2 fișiere JS: main_de.js , element_main.js

Cele două fișiere JavaScript sunt ascunse și minimizate. Instrumente precum JS Nice și de4js ne ajută acum să facem aceste fișiere mai lizibile. Pentru a le depana în direct, recomandăm Chrome Extension Requestly, care tunelează fișierele la distanță local pe loc:

Acum putem depana codul ( CORS trebuie mai întâi activat pe serverul local). Secțiunea de cod relevantă pentru generarea simbolului pare a fi ascunsă în fișierul element_main.js din această secțiune:

b7739bf50b2edcf636c43a8f8910def9

Aici textul este hash cu ajutorul unor schimbări de biți . Dar, din păcate, încă ne lipsește o piesă din puzzle: pe lângă argumentul a (care este textul de tradus), un alt argument b este trecut la funcția Bp () - un fel de sămânță care pare să se schimbe din când în când și care include și se varsă în hashing. Dar de unde vine? Dacă trecem la apelul funcției Bp () , vom găsi următoarea secțiune de cod:

b7739bf50b2edcf636c43a8f8910def9

Funcția Hq este declarată în prealabil după cum urmează:

b7739bf50b2edcf636c43a8f8910def9

Deobfuscaterul a lăsat aici niște gunoaie; După ce am înlocuit String.fromCharCode ('...') cu șirurile de caractere respective, eliminați a () învechit și compuneți funcția apelează [c (), c ()] , rezultatul este:

b7739bf50b2edcf636c43a8f8910def9

Sau chiar mai ușor:

b7739bf50b2edcf636c43a8f8910def9

Funcția yq este definită anterior ca:

b7739bf50b2edcf636c43a8f8910def9

Semințele par să se afle în obiectul global google.translate._const._ctkk , care este disponibil la runtime. Dar unde este pus? În celălalt fișier JS încărcat anterior main_de.js, cel puțin este disponibil și la început. Adăugăm următoarele la început:

b7739bf50b2edcf636c43a8f8910def9

În consolă obținem de fapt semința curentă:

Acest lucru lasă Google Chrome însuși, care se pare că oferă semințe, ca ultimă opțiune. Din fericire, codul său sursă (Chromium, inclusiv componenta Translate) este open source și, prin urmare, este disponibil publicului. Tragem depozitul local și găsim apelul către funcția TranslateScript :: GetTranslateScriptURL în fișierul translate_script.cc din folderul components / translate / core / browser:

b7739bf50b2edcf636c43a8f8910def9

Variabila cu adresa URL este definită în același fișier:

b7739bf50b2edcf636c43a8f8910def9

Dacă examinăm acum fișierul element.js mai îndeaproape (după dezobscurarea din nou), găsim intrarea hard-set c._ctkk - obiectul google.translate este, de asemenea, setat corespunzător și încărcarea tuturor activelor relevante (pe care le-am descoperit deja mai devreme) este declanșată:

b7739bf50b2edcf636c43a8f8910def9

Acum cheia parametrului rămâne de luat în considerare (cu valoarea AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw). Aceasta pare a fi o cheie API generică pentru browser (care poate fi găsită și în unele rezultate Google ). Este setat în Chromium în fișierul translate_url_util.cc din folderul components / translate / core / browser:

b7739bf50b2edcf636c43a8f8910def9

Cheia este generată în google_apis / google_api_keys.cc dintr-o valoare fictivă:

b7739bf50b2edcf636c43a8f8910def9

Cu toate acestea, un test arată că apelurile API funcționează la fel fără acest parametru cheie. Dacă experimentați cu API-ul, veți primi codul de stare 200 înapoi, dacă aveți succes. Dacă vă confruntați cu o limită, primiți codul de stare 411 înapoi cu mesajul „ Cererile POST necesită un antet de lungime de conținut ”. Prin urmare, este recomandabil să includeți acest antet (care este setat automat ca antet temporar în Postman).

Formatul de returnare a șirurilor traduse este neobișnuit atunci când există mai multe propoziții într-o singură cerere. Frazele individuale sunt incluse în etichetele i- / b-HTML:

De asemenea, Google Chrome nu trimite întregul HTML către API, ci salvează valori ale atributelor precum href în cerere (și, în schimb, stabilește indicii, astfel încât etichetele să poată fi atribuite ulterior pe partea clientului):

Dacă modificați valoarea clientului cheie POST din te_lib (Google Chrome) pe webapp ( site-ul web Traducere Google ), veți obține șirul final tradus:

Problema este că sunteți mult mai probabil să vă confruntați cu limitarea ratei decât prin te_lib (pentru comparație: cu webapp acest lucru este atins după 40.000 de caractere, cu te_lib nu există o limitare a ratei). Deci, trebuie să analizăm mai atent modul în care Chrome analizează rezultatul. O vom găsi aici în element_main.js:

b7739bf50b2edcf636c43a8f8910def9

Dacă trimiteți întregul cod HTML către API, acesta lasă atributele în răspunsul tradus. Prin urmare, nu trebuie să imităm întregul comportament al analizei, ci doar să extragem șirul final tradus din răspuns. Pentru a face acest lucru, construim un mic analizator HTML care elimină etichetele <i> exterioare, inclusiv conținutul acestora și elimină etichetele <b> exterioare. Având în vedere acest lucru, putem acum să construim o versiune de server a API-ului de traducere:

b7739bf50b2edcf636c43a8f8910def9

Următoarele sunt rezultatele unui test inițial care a fost efectuat pe cinci sisteme diferite cu lățimi de bandă diferite și adrese IP:

CaracterCaracterele pe cerereDuratăRata de eroareCost prin API oficial
13.064.662~25003: 36: 17h0%237,78€
24.530.510~25011: 09: 13h0%446,46€
49.060.211~25020: 39: 10h0%892,90€
99.074.487~100061: 24: 37h0%1803,16€
99.072.896~100062: 22: 20h0%1803,13€
Σ284.802.766~ Ø550Σ159: 11: 37h0%Σ 5183,41 €

Notă: Această postare de blog, care include toate scripturile, a fost scrisă doar în scop de testare. Nu folosiți scripturile pentru utilizare productivă, în loc să lucreze cu oficial API - ul Google de traducere .

Înapoi