Google翻译API黑客攻击

作为其Google Cloud的一部分,Google为Google Translation API提供了基于使用情况的费用结构。 还有一个未记录的API ,可以不使用key来使用,但仅在几次请求后就拒绝工作。 使用Google Chrome浏览器的网站翻译功能时,值得注意的是,页面的翻译质量非常好,没有任何明显的限制。


显然,这里已经使用了高级nmt模型。 但是,谷歌浏览器内部使用哪种API来翻译内容,并且即使在服务器端,也可以直接使用该API吗? 要分析网络流量,建议使用WiresharkTelerik Fiddler之类的工具,它们也可以分析加密的流量。 但是Chrome甚至可以免费发送它发送的页面翻译请求:可以使用Chrome DevTools轻松查看它们:

如果进行翻译,则通过“复制>复制为cURL(bash)”将关键的POST请求捕获到https://translate.googleapis.com并在Postman之类的工具中执行它,例如,您可以再次发送请求而不会出现任何问题:

URL参数的含义也很明显:

示例值含义
安诺3注释模式(影响返回格式)
客户te_lib客户信息(可变,值通过Google Translate网络界面为“ webapp”;会影响返回格式和速率限制)
格式html字符串格式(对于翻译HTML标签很重要)
v1.0Google翻译版本号
AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgwAPI密钥(请参见下文)
对数vTE_20200210_00协议版本
sl源语言
tl目标语言
SP纳米ML模型
tc1未知
sr1未知
k709408.812158令牌(见下文)
时尚1未知

还设置了一些请求标头-但这些标头通常可以忽略。 手动取消选择所有标头(包括来自用户代理的标头)后,在输入特殊字符时(此处是翻译“ Hello World ”时),发现编码问题:

如果您重新激活用户代理(通常不会造成任何伤害),则该API会传递UTF-8编码的字符:

我们已经在这里了吗,我们是否拥有在Chrome浏览器之外使用此API的所有信息? 如果将要转换的字符串(POST请求的数据字段q )从“ Hello world”更改为“ Hello world “,我们收到一条错误消息:

现在,我们使用网站翻译功能在Google Chrome浏览器中再次翻译了修改后的内容,发现除了参数q之外,参数tk也已更改(所有其他参数均保持不变):

显然,这是一个依赖于字符串的令牌,其结构不容易看到。 当您开始网站翻译时,将加载以下文件:

  • 1个CSS文件: translateelement.css
  • 4个图形: translate_24dp.png (2x), gen204 (2x)
  • 2个JS文件: main_de.jselement_main.js

这两个JavaScript文件被混淆并缩小。 JS Nicede4js之类的工具现在正在帮助我们使这些文件更具可读性。 为了实时调试它们,我们建议使用Chrome扩展程序,它可以动态地在本地传输远程文件:

现在我们可以调试代码了(必须先在本地服务器上激活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

在控制台中,我们实际上获得了当前种子:

剩下的就是谷歌浏览器本身了,后者显然提供了种子。 幸运的是,其源代码(Chromium,包括Translate组件)是开源的,因此可以公开获得。 我们将存储库拉到本地,然后在components / translate / core / browser文件夹中的translate_script.cc文件中找到对TranslateScript :: GetTranslateScriptURL函数的调用:

b7739bf50b2edcf636c43a8f8910def9

带有URL的变量在同一文件中硬定义:

b7739bf50b2edcf636c43a8f8910def9

如果现在我们更仔细地检查一下element.js文件(再次对其进行模糊处理之后),我们会发现硬设置条目c._ctkk - google.translate对象也进行了相应设置,并且触发了所有相关资产(我们之前已经发现过)的加载:

b7739bf50b2edcf636c43a8f8910def9

现在,参数仍在考虑中(值为AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw)。 这似乎是通用的浏览器API密钥(也可以在某些Google结果中找到)。 它在Chromium中的components / translate / core / rows文件夹中的文件translate_url_util.cc中设置。:

b7739bf50b2edcf636c43a8f8910def9

该密钥是从哑数值google_apis / google_api_keys.cc中生成的:

b7739bf50b2edcf636c43a8f8910def9

但是,测试表明,没有此关键参数,API调用的工作原理相同。 如果您尝试使用该API,则如果成功,您将获得状态码200 。 如果随后遇到限制,则会返回状态代码411 ,并显示消息“ POST请求需要内容长度的标头”。 因此,建议包括此标头(在Postman中自动设置为临时标头)。

当一个请求中包含多个句子时,翻译后的字符串的返回格式不常见。 各个句子用i- / b-HTML标记括起来:

另外,谷歌浏览器不会将完整的HTML发送给API,而是在请求中保存href等属性值(并设置索引,以便以后可以在客户端分配标签):

如果您从te_lib (Google Chrome)更改POST密钥客户端的值 webappGoogle翻译网站)上,您将获得最终的翻译字符串:

问题是,与通过te_lib相比,您更有可能遇到速率限制(为进行比较:对于webapp,这是在40,000个字符之后达到的,而te_lib没有速率限制)。 因此,我们需要仔细研究Chrome如何解析结果。 我们将在element_main.js中找到它:

b7739bf50b2edcf636c43a8f8910def9

如果将整个HTML代码发送到API,它将属性保留在转换后的响应中。 因此,我们不必模仿整个解析行为,而只需从响应中提取最终的翻译字符串。 为此,我们构建了一个小的HTML标签解析器,该解析器丢弃最外面的<i>标签(包括其内容)并删除最外面的<b>标签。 考虑到这一点,我们现在可以构建服务器端版本的翻译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

背部