Google Apps脚本 - 如何登录和获取数据?

时间:2014-10-11 00:19:43

标签: javascript post login google-apps-script urlfetch

说明:
我很缺乏经验,但最近我一直试图使用Google Apps Scripts从网站访问一些数据。但是,要访问数据,我必须登录该网站。实际上之前有很多关于类似问题的帖子,但在我找到这个问题之前,它们都没有帮助:how to fetch a wordpress admin page using google apps script。接受的答案提供了一种方法,用于保存cookie并在第二个请求中再次发送它们。我基本上将代码复制并粘贴到我自己的GAS文件中。由于该帖子中的问题是登录到Wordpress,我首先尝试了它,并且它有效。我不得不删除if语句检查响应代码,因为即使我输入了正确的组合,也会返回200。我不知道这只是帖子代码中的错误或者是什么。在任何情况下,我都验证了我发出的第二个请求返回的信息就像我已登录一样。

有关特定网站的详细信息:
我尝试登录的实际网站有一种奇怪的哈希方法,我在其他任何登录页面上都看不到。单击“提交”时,密码会在转到另一个页面之前变为很长时间。开始表格标签如下所示:

<form action="/guardian/home.html" method="post" name="LoginForm" target="_top" id="LoginForm" onsubmit="doPCASLogin(this);">

正如你所看到的,它有一个&#34; onsubmit&#34;属性,我相信它只会运行&#34; doPCASLogin(this);&#34;提交表单时。我决定只通过在地址栏中输入javascript来玩这个页面。我发现这样做的命令(输入我的用户名和密码后):

javascript: document.forms[0].submit();

没有工作。所以我挖了一下,找到了函数&#34; doPCASLogin()&#34;在一个名为&#34; md5.js&#34;的javascript文件中。我相信md5是某种哈希算法,但这并不重要。 &#34; doPCASLogin()&#34;的重要部分是这样的:

function doPCASLogin(form) {
   var originalpw = form.pw.value;
   var b64pw = b64_md5(originalpw);
   var hmac_md5pw = hex_hmac_md5(pskey, b64pw)
   form.pw.value = hmac_md5pw;
   form.dbpw.value = hex_hmac_md5(pskey, originalpw.toLowerCase())
   if (form.ldappassword!=null) {
     form.ldappassword.value = originalpw;
   }
}

还有一些其他的东西,但我发现它对我的登录并不重要。很明显,这只是通过另一个函数运行密码几次使用&#34; pskey&#34; (存储在隐藏的输入中,每次重新加载时不同)作为键,并将它们放在原始表单的输入中(&#34; dbpw&#34;和&#34; ldappassword&#34;是隐藏的输入,而&# 34; pw&#34;是可见的密码输入输入)。在它完成后,它提交。我找到了另一个&#34; hex_hmac_md5()&#34;函数,实际上连接到一大堆其他函数来散列密码。无论如何,这并不重要,因为我可以调用&#34; hex_hmac_md5()&#34;从我在地址栏中输入的javascript中输入。这是我提出的工作代码,我只是为了可读性而打破了界限:

javascript:
document.forms['LoginForm']['account'].value="username";
document.forms['LoginForm']['pw'].value="hex_hmac_md5(pskey, b64_md5('password');)";
document.forms['LoginForm']['ldappassword'].value="password";
document.forms['LoginForm']['dbpw'].value="hex_hmac_md5(pskey, 'password')";
document.forms['LoginForm'].submit();

无论你在哪里看到&#34;用户名&#34;或者&#34;密码&#34;,这只是意味着我在这些地方输入了我的用户名和密码,但显然我已经删除了它们。当我发现这有效时,我写了一个小的Chrome扩展程序,当我访问网站时会自动登录(登录过程很奇怪,因此Chrome不记得我的用户名和密码)。这很好,但这不是我的最终目标。

困境:
在发现关于散列的所有这些之后,我尝试将所有这些值放入我的GAS文件中的HTTP有效负载中,尽管我怀疑它是否有效。它没有,我怀疑这是因为值只是作为字符串读取而javascript实际上并没有运行。这是有道理的,因为运行实际的javascript可能是一个安全问题。但是,为什么它会在地址栏中工作呢?就像旁注一样,我收到了200响应代码,而且似乎也发送了一个cookie,尽管它可能无效。当我读到实际响应时,它只是登录页面。

我也考虑过在看到这个问题之后尝试在我自己的代码中复制整个函数:How to programmatically log into a website?,但是因为&#34; pskey&#34;每次重新加载时都不同,我认为必须使用第二个UrlFetch上的新密钥完成散列。因此,即使我将所有功能复制到我的GAS文件中,我也不认为我可以成功登录,因为我需要知道&#34; pskey&#34;在实际发送请求之前将为特定请求生成,这是不可能的。唯一可行的方法是,如果我能以某种方式维护一个页面并在发送数据之前阅读它,但我不知道如何使用GAS进行此操作。

编辑:我找到了另一个名为&#34; contextData&#34;的输入,它与&#34; pskey&#34;相同。加载页面时。但是,如果我登录一次并查看使用Chrome开发者工具发出的POST请求,我可以复制所有输入值,包括&#34; contextData&#34;,然后我可以再次发送另一个请求。在地址栏中使用javascript,它看起来像这样:

javascript:
document.forms['LoginForm']['account'].value="username";
document.forms['LoginForm']['pw'].value="value in field that browser sent once";
document.forms['LoginForm']['ldappassword'].value="password";
document.forms['LoginForm'['dbpw'].value="value in field that browser sent once";
document.forms['LoginForm'['contextData'].value="value in field that browser sent once";
document.forms['LoginForm'].submit();

我可以用这种方式多次登录网站,无论是什么&#34; pskey&#34;因为我直接提交所有内容而且没有进行散列。但是,这对我来说仍然不起作用,所以我有点卡住了。我应该注意到我已经检查了其他隐藏的输入字段,即使清除了表单中的每个输入,我仍然可以使用上面的javascript成功登录。

问题:
- 假设我发送的代码被解释为字符串,我是否正确? - 为什么我刚才写的新代码不起作用? - 为了将来参考,我如何使用GAS登录Google这样的网站,其中在登录表单中发送随机生成的字符串,并且必须将其发回?

function getData() {
  var loginURL = 'login page';
  var dataURL = 'page with data';
  var loginPayload = {
     'account':'same as in previous code block',
     'pw':"same as in previous code block",
     'ldappassword':'same as in previous code block',
     'dbpw':"same as in previous code block",
     "contextData":"same as in previous code block",
  };
  var loginOptions = {'method':'post','payload':loginPayload,'followredirects':false};
  var loginResponse = UrlFetchApp.fetch(loginURL,loginOptions);

  var loginHeaders = loginResponse.getAllHeaders();
  var cookie = [loginResponse.getAllHeaders()["Set-Cookie"]];
  cookie[0] = cookie[0].split(";")[0];
  cookie = cookie.join(";");

  var dataHeaders = {'Cookie':cookie};
  var dataOptions = {'method':'get','headers':dataHeaders};
  var dataResponse = UrlFetchApp.fetch(dataURL,dataOptions);

  Logger.log(dataResponse);
}

1 个答案:

答案 0 :(得分:0)

某种我在其他任何登录页面上都未见过的奇怪的哈希方法

此登录名使用MD5 hashing algorithm密码中的著名base-64 encoded(注意,对于数据库访问dbpw,它使用相同的密码,但使用小写字母,并且具有发送LDAP登录密码的明文(!)版本的选项。

在实际发送请求之前,知道为特定请求生成的“ pskey”,这是不可能的

pskey仅存储用于计算HMAC签名的密钥。没什么能阻止您对其进行硬编码,从磁盘读取,生成它或从远程获取的,无论何时何地(显然是在计算之前)。

运行实际的javascript可能是安全问题

尽管运行不受信任的JavaScript代码确实是一个安全问题,但这并不是您所遇到的全部情况。有关原因的详细说明,请参见下一点。您应该做的是实际上运行散列函数(在2020年,您需要在这方面使用Utilities服务provides everything),然后再将其分配给{{1} }属性。

我是否假设我发送的代码被解释为字符串是正确的?

引号中的所有内容(单引号或双引号)均视为一个字符序列。这不是Google Apps脚本的工作方式,而是ECMAScript(基于它)设计的工作方式。为了在字符串“内部”执行函数,您需要使用loginPayload,但请 never do that

现在,在2020年,我花了一些时间来记住eval协议的含义。这是您的代码首先执行的唯一原因-您明确告诉浏览器,接下来是要执行的JavaScript代码。如果有人看到此内容:请再次 don't use

Google Apps脚本是服务器端的代码,并且不会在浏览器环境中执行,因此,即使您确实使用了该协议,它也不会生效,因为未进行任何评估。< / p>

为什么我最近写的下面的新代码不起作用?

由于上述所有原因。

供将来参考,我将如何使用GAS登录Google之类的网站,在该网站中以登录形式发送随机生成的字符串,并且必须将其发送回去?

如果您正在谈论OAuth / OAuth2.0身份验证协议,以下是专门用于此目的的正式endorsed library