Google Oversæt API Hacking

Google tilbyder Google Translation API med en brugsbaseret omkostningsstruktur som en del af sin Google Cloud. Der er også en udokumenteret API, der kan bruges uden nøgle , men som nægter at arbejde efter blot et par anmodninger. Når du bruger webstedsoversættelsesfunktionen i Google Chrome, bemærkes det, at sider kan oversættes i meget god kvalitet uden nogen mærkbar begrænsning.


Tilsyneladende bruges den avancerede nmt-model allerede her. Men hvilken API bruger Google Chrome internt til at oversætte indholdet, og kan denne API også adresseres direkte - selv på serversiden? For at analysere netværkstrafik anbefales værktøjer som Wireshark eller Telerik Fiddler , som også kan analysere krypteret trafik. Men Chrome leverer endda de anmodninger, den sender til sideoversættelsen gratis: De kan let ses ved hjælp af Chrome DevTools:

Hvis du udfører en oversættelse, skal du fange den afgørende POST-anmodning til https://translate.googleapis.com via "Kopiér> Kopier som cURL (bash)" og udføre den i et værktøj som Postman , for eksempel kan du sende anmodningen igen uden problemer:

Betydningen af ​​URL-parametrene er også stort set indlysende:

NøgleEksempel værdiBetyder
anno3Annotationstilstand (påvirker returformatet)
klientte_libKlientinformation (varierer, værdien er "webapp" via Google Translate's webgrænseflade; har en indvirkning på returformatet og hastighedsbegrænsningen)
formathtmlStrengformat (vigtigt for oversættelse af HTML-tags)
v1.0Google Translate-versionsnummer
nøgleAIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwAPI-nøgle (se nedenfor)
logldvTE_20200210_00Protokolversion
sldeKildesprog
tldaMål sprog
spnmtML-model
tc1ukendt
sr1ukendt
tk709408.812158Token (se nedenfor)
Mode1ukendt

Nogle anmodningsoverskrifter er også indstillet - men disse kan for det meste ignoreres. Efter manuelt fravælgelse af alle overskrifter, inklusive dem fra brugeragenten , opdages et kodningsproblem, når der indtastes specialtegn (her når man oversætter " Hello World "):

Hvis du genaktiverer brugeragenten (som normalt ikke skader), leverer API'et UTF-8-kodede tegn:

Er vi der allerede, og har vi alle oplysninger til at bruge denne API uden for Google Chrome? Hvis du ændrer strengen, der skal oversættes (datafelt q i POST-anmodningen) fra for eksempel “Hello world” til “Hello world ! “Vi får en fejlmeddelelse:

Vi oversætter nu denne modificerede igen i Google Chrome ved hjælp af webstedsoversættelsesfunktionen og finder ud af, at parameteren tk , ud over parameteren q , også har ændret sig (alle andre parametre har været de samme):

Det er åbenbart et token, der afhænger af strengen, hvis struktur ikke er let at se. Når du starter oversættelsen af ​​hjemmesiden, indlæses følgende filer:

  • 1 CSS-fil: translateelement.css
  • 4 grafik: translate_24dp.png (2x), gen204 (2x)
  • 2 JS-filer: main_de.js , element_main.js

De to JavaScript-filer tilsløres og formindskes. Værktøjer som JS Nice og de4js hjælper os nu med at gøre disse filer mere læsbare. For at fejle dem live anbefaler vi Chrome Extension Requestly, som tunneler fjernfiler lokalt på farten:

Nu kan vi fejle koden ( CORS skal først aktiveres på den lokale server). Det relevante kodeafsnit til generering af tokenet ser ud til at være skjult i filen element_main.js i dette afsnit:

b7739bf50b2edcf636c43a8f8910def9

Her hashes teksten ved hjælp af nogle bitskift . Men desværre mangler vi stadig et stykke af puslespillet: Ud over argumentet a (som er teksten, der skal oversættes), overføres et andet argument b til funktionen Bp () - en slags frø, der synes at ændre sig fra tid til anden, og som også inkluderer flyder ind i hashing. Men hvor kommer han fra? Hvis vi hopper til funktionsopkaldet til Bp () , finder vi følgende kodeafsnit:

b7739bf50b2edcf636c43a8f8910def9

Funktionen Hq er på forhånd erklæret som følger:

b7739bf50b2edcf636c43a8f8910def9

Deobfuscater har efterladt noget affald her; Når vi har udskiftet String.fromCharCode ('...') med de respektive tegnstrenge, skal du fjerne det forældede a () og sammensætte funktionen kald [c (), c ()] , resultatet er:

b7739bf50b2edcf636c43a8f8910def9

Eller endnu lettere:

b7739bf50b2edcf636c43a8f8910def9

Funktionen yq er tidligere defineret som:

b7739bf50b2edcf636c43a8f8910def9

Frøet ser ud til at være i det globale objekt google.translate._const._ctkk , som er tilgængeligt under kørsel. Men hvor er det sat? I den anden, tidligere indlæste JS-fil main_de.js, er den i det mindste også tilgængelig i begyndelsen. Vi tilføjer følgende i starten:

b7739bf50b2edcf636c43a8f8910def9

I konsollen får vi faktisk det nuværende frø:

Dette efterlader Google Chrome selv, som tilsyneladende giver frøet, som den sidste mulighed. Heldigvis er dens kildekode (Chrom, inklusive Translate-komponenten) open source og derfor offentligt tilgængelig. Vi trækker arkivet lokalt og finder opkaldet til TranslateScript :: GetTranslateScriptURL- funktionen i translate_script.cc- filen i komponenterne / translate / core / browser- mappen:

b7739bf50b2edcf636c43a8f8910def9

Variablen med URL'en er hårdt defineret i den samme fil:

b7739bf50b2edcf636c43a8f8910def9

Hvis vi nu undersøger filen element.js nærmere (efter at deobfuscating det igen), finder vi den hårde indstilling c._ctkk - google.translate- objektet indstilles også i overensstemmelse hermed, og indlæsningen af ​​alle relevante aktiver (som vi allerede har opdaget tidligere) udløses:

b7739bf50b2edcf636c43a8f8910def9

Nu parameter nøglen fjernes til overvejelse (med værdien AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw). Det ser ud til at være en generisk browser-API-nøgle (som også kan findes i nogle Google-resultater ). Det er indstillet i Chromium i filen translate_url_util.cc i mappekomponenterne / translate / core / browser:

b7739bf50b2edcf636c43a8f8910def9

Nøglen genereres i google_apis / google_api_keys.cc fra en dummy-værdi:

b7739bf50b2edcf636c43a8f8910def9

En test viser imidlertid, at API-opkald fungerer det samme uden denne nøgleparameter. Hvis du eksperimenterer med API'en, får du statuskoden 200 tilbage, hvis du har succes. Hvis du derefter løber ind i en grænse, får du statuskoden 411 tilbage med meddelelsen " POST-anmodninger kræver en indholdslængdeoverskrift ". Det tilrådes derfor at medtage dette header (som automatisk indstilles som et midlertidigt header i Postman).

Returneringsformatet for de oversatte strenge er usædvanligt, når der er flere sætninger i en anmodning. De enkelte sætninger er lukket af i- / b-HTML-tags:

Google Chrome sender heller ikke hele HTML til API'et, men gemmer attributværdier som href i anmodningen (og indstiller i stedet indekser, så tags senere kan tildeles på klientsiden):

Hvis du ændrer værdien af POST nøglen klient fra te_lib (Google Chrome) webapp ( Google Oversættelseswebsted ) får du den endelige oversatte streng:

Problemet er, at du er meget mere tilbøjelige til at løbe ind i hastighedsbegrænsning end via te_lib (til sammenligning: med webapp nås dette efter 40.000 tegn, med te_lib er der ingen hastighedsbegrænsning). Så vi er nødt til at se nærmere på, hvordan Chrome analyserer resultatet. Vi finder det her i element_main.js:

b7739bf50b2edcf636c43a8f8910def9

Hvis du sender hele HTML-koden til API'et, efterlader den attributterne i det oversatte svar. Vi behøver derfor ikke at efterligne hele parseadfærden, men kun udtrække den endelige, oversatte streng fra svaret. For at gøre dette bygger vi en lille HTML-tag-parser, der kasserer de yderste <i>-tags inklusive deres indhold og fjerner de yderste <b>-tags. Med denne viden (efter installation af afhængigheder med komponist kræver fzaninotto / faker vielhuber / stringhelper ) kan vi nu bygge en server-side version af oversættelses API:

b7739bf50b2edcf636c43a8f8910def9

Følgende er resultaterne af en indledende test, der blev udført på fem forskellige systemer med forskellige båndbredder og IP-adresser:

KarakterTegn pr. AnmodningVarighedFejlrateOmkostninger via officiel API
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

Bemærk: Dette blogindlæg inklusive alle scripts blev kun skrevet til testformål. Brug ikke scripts til produktiv brug, i stedet for at arbejde med den officielle Google Translation API .

Tilbage