Google-översättning API-hacking

Google erbjuder API för Google Översättning med en användningsbaserad kostnadsstruktur som en del av Google Cloud. Det finns också ett odokumenterat API som kan användas utan nyckel , men som vägrar att fungera efter bara några få förfrågningar. När du använder webbplatsens översättningsfunktion i Google Chrome märks det att sidor kan översättas i mycket god kvalitet utan någon märkbar begränsning.


Tydligen används den avancerade nmt-modellen redan här. Men vilket API använder Google Chrome internt för att översätta innehållet och kan detta API också adresseras direkt - även på serversidan? För att analysera nätverkstrafik rekommenderas verktyg som Wireshark eller Telerik Fiddler , som också kan analysera krypterad trafik. Men Chrome levererar till och med de förfrågningar som den skickar om sidöversättningen utan kostnad : De kan enkelt ses med hjälp av Chrome DevTools:

Om du utför en översättning, fånga den viktiga POST-begäran till https://translate.googleapis.com via "Kopiera> Kopiera som cURL (bash)" och kör den i ett verktyg som Postman , till exempel kan du skicka begäran igen utan problem:

Betydelsen av URL-parametrarna är också till stor del uppenbar:

NyckelExempelvärdeMenande
anno3Kommentarläge (påverkar returformatet)
klientte_libKundinformation (varierar, värdet är "webapp" via Google Translate webbgränssnitt; påverkar returformatet och hastighetsbegränsningen)
formaterahtmlSträngformat (viktigt för att översätta HTML-taggar)
v1.0Google Translate-versionsnummer
nyckel-AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwAPI-nyckel (se nedan)
logldvTE_20200210_00Protokollversion
sldeKällspråk
tlsvMålspråk
spnmtML-modell
tc1okänd
sr1okänd
tk709408.812158Token (se nedan)
Mode1okänd

Vissa förfrågningsrubriker är också inställda - men dessa kan oftast ignoreras. Efter manuell avmarkering av alla rubriker, inklusive de från användaragenten , upptäcks ett kodningsproblem när man skriver in specialtecken (här när man översätter " Hello World "):

Om du återaktiverar användaragenten (som vanligtvis inte skadar), levererar API: t UTF-8-kodade tecken:

Är vi redan där och har vi all information för att använda detta API utanför Google Chrome? Om du ändrar strängen som ska översättas (datafält q i POST-förfrågan) från till exempel “Hello world” till “Hello world ! ”, Vi får ett felmeddelande:

Vi översätter nu den modifierade igen i Google Chrome med hjälp av webbplatsöversättningsfunktionen och finner att, förutom parametern q , har parametern tk också ändrats (alla andra parametrar har förblivit desamma):

Uppenbarligen är det en symbol som beror på strängen vars struktur inte är lätt att se. När du startar webbplatsöversättningen laddas följande filer:

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

De två JavaScript-filerna fördunklas och förminskas. Verktyg som JS Nice och de4js hjälper oss nu att göra dessa filer mer läsbara. För att felsöka dem live rekommenderar vi Chrome Extension Requestly, som tunnlar fjärrfiler lokalt i farten:

Nu kan vi felsöka koden ( CORS måste först aktiveras på den lokala servern). Det relevanta kodavsnittet för att generera token verkar vara dolt i det här avsnittet i filen element_main.js:

b7739bf50b2edcf636c43a8f8910def9

Här hashas texten med hjälp av några bitskift . Men tyvärr saknar vi fortfarande en bit i pusslet: Förutom argumentet a (som är texten som ska översättas) skickas ett annat argument b till funktionen Bp () - ett slags frö som verkar förändras från tid till annan och som också inkluderar flyter in i hashing. Men var kommer han ifrån? Om vi ​​hoppar till funktionsanropet till Bp () hittar vi följande kodavsnitt:

b7739bf50b2edcf636c43a8f8910def9

Funktionen Hq deklareras i förväg enligt följande:

b7739bf50b2edcf636c43a8f8910def9

Här lämnade Deobfuscater lite skräp; När vi har ersatt String.fromCharCode ('...') med respektive teckensträngar, ta bort det föråldrade a () och sätt ihop funktionen kallar [c (), c ()] , resultatet är:

b7739bf50b2edcf636c43a8f8910def9

Eller ännu enklare:

b7739bf50b2edcf636c43a8f8910def9

Funktionen yq har tidigare definierats som:

b7739bf50b2edcf636c43a8f8910def9

Fröet verkar finnas i det globala objektet google.translate._const._ctkk , som är tillgängligt vid körning. Men var är den inställd? I den andra, tidigare laddade JS-filen main_de.js finns den åtminstone också i början. Vi lägger till följande i början:

b7739bf50b2edcf636c43a8f8910def9

I konsolen får vi faktiskt det aktuella fröet:

Detta lämnar Google Chrome själv, som tydligen ger fröet, som det sista alternativet. Lyckligtvis är dess källkod (Chromium, inklusive Translate-komponenten) öppen källkod och därför allmänt tillgänglig. Vi drar förvaret lokalt och hitta samtalet till TranslateScript :: GetTranslateScriptURL funktion i translate_script.cc filen i komponenter / översätta / core / mapp webbläsare:

b7739bf50b2edcf636c43a8f8910def9

Variabeln med URL: en är hårt definierad i samma fil:

b7739bf50b2edcf636c43a8f8910def9

Om vi ​​nu undersöker filen element.js närmare (efter att deobfuscating igen), hittar vi den hårda uppsättningen c._ctkk - google.translate- objektet ställs också in och laddningen av alla relevanta tillgångar (som vi redan har upptäckt tidigare) utlöses:

b7739bf50b2edcf636c43a8f8910def9

Nu de parameternyckel resterna för övervägande (med värdet AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw). Det verkar vara en generisk webbläsar-API-nyckel (som också finns i vissa Google-resultat ). Den ställs in i Chromium i filen translate_url_util.cc i mappkomponenterna / translate / core / browser:

b7739bf50b2edcf636c43a8f8910def9

Nyckeln genereras i google_apis / google_api_keys.cc från ett dummyvärde:

b7739bf50b2edcf636c43a8f8910def9

Ett test visar dock att API-samtalen fungerar på samma sätt utan den här nyckelparametern. Om du experimenterar med API: et får du statuskoden 200 tillbaka om du lyckas. Om du sedan stöter på en gräns får du tillbaka statuskoden 411 med meddelandet " POST-förfrågningar kräver en innehållslängdhuvud ". Det rekommenderas därför att inkludera denna rubrik (som automatiskt ställs in som en tillfällig rubrik i Postman).

Returformatet för de översatta strängarna är ovanligt när det finns flera meningar i en begäran. De enskilda meningarna omges av i- / b-HTML-taggarna:

Google Chrome skickar inte heller den fullständiga HTML-koden till API: et, utan sparar attributvärden som href i begäran (och ställer istället index så att taggarna senare kan tilldelas på klientsidan):

Om du ändrar värdet för POST nyckel klienten från te_lib (Google Chrome) webapp ( Googles översättningswebbplats ) får du den slutliga översatta strängen:

Problemet är att du är mycket mer benägna att stöta på hastighetsbegränsning än via te_lib (för jämförelse: med webapp nås detta efter 40 000 tecken, med te_lib finns det ingen hastighetsbegränsning). Så vi måste titta närmare på hur Chrome analyserar resultatet. Vi hittar det här i element_main.js:

b7739bf50b2edcf636c43a8f8910def9

Om du skickar hela HTML-koden till API lämnar den attributen i det översatta svaret. Vi behöver därför inte imitera hela analysuppförandet, utan endast extrahera den slutliga, översatta strängen från svaret. För att göra detta bygger vi en liten HTML-taggparser som kasserar de yttersta <i> taggarna inklusive deras innehåll och tar bort de yttersta <b> taggarna. Med detta i åtanke kan vi nu bygga en serverversion av översättnings-API: et:

b7739bf50b2edcf636c43a8f8910def9

Följande är resultaten av ett första test som utfördes på fem olika system med olika bandbredd och IP-adress:

KaraktärTecken per begäranVaraktighetFelprocentKostnad via officiellt 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 €

Obs! Det här blogginlägget inklusive alla skript skrevs bara för teständamål. Använd inte skript för produktiv användning, istället arbeta med det officiella Google Translation API .

Tillbaka