【问题标题】:Is this setup of using a webapp and api executable secure and reasonable?这种使用 webapp 和 api 可执行文件的设置是否安全合理?
【发布时间】:2019-08-02 11:26:30
【问题描述】:

问题

我们(我和一位同事)有一些代码非常适合 webapp 的用例,但我们域外的用户身份验证除外。如果不是因为这个问题,我们本来希望使用以下配置(在我们的清单文件的顶层)。

"webapp": {
  "access": "ANYONE",
  "executeAs": "USER_DEPLOYING"}

对于我们域内的用户,我们可以使用Session.getActiveUser()。然后,我们可以将其与我们的数据库进行比较,并显示应该只对该帐户可见的敏感数据。

然而,对于我们域之外的用户,Session.getActiveUser() 给出了空字符串'',所以我们不能用它来查询我们数据库中的信息,所以我们需要一些不同的东西。我们想出的是以下设置。

替代设置

我们使用"executeAs": "USER_ACCESSING""oauthScopes": ["https://www.googleapis.com/auth/userinfo.email"] 部署webapp。我们使用特权帐户将另一个脚本部署为 API 可执行文件(并遵循说明here)。 webapp 的主 Code.gs 文件如下所示。

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index.html');
}

function getUserBackendData(){
  //works for users outside our domain
  var activeUserEmail = Session.getActiveUser();

  var apiKey = 'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabc'
  var scriptId = 'ababababababababababababababababababababababab';
  var token = 'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd'; //very secret

  var url = 'https://script.googleapis.com/v1/scripts/'+ scriptId +':run?key='+ apiKey;
  var functionCallData = 
      {
        "function": 'retrieveData',
        "parameters": [activeUserEmail],
        "devMode": false};
  var options = {
    'method' : 'post',
    'contentType': 'application/json',
    'payload' : JSON.stringify(functionCallData),
    'headers': {'Authorization': 'Bearer '+  token}
  };

  return UrlFetchApp.fetch(url, options).getContentText();
}

我们的想法是,这允许我们以特权用户身份在我们的 API 可执行文件中执行函数 retrieveData(activeUserEmail),同时使用 webapp 来找出访问该应用程序的用户的电子邮件地址。 Session.getActiveUser() 现在适用于我们域外的用户的原因是我们部署为 "executeAs": "USER_ACCESSING"

问题

我们担心的是 1) 有一种更简单/更好的方法来执行此操作,以及 2) 访问 webapp 的用户可以以某种方式检索用于调用 api 可执行文件中的函数的令牌,我们担心这可能会被用来窃取私人数据。

This Q&A 涉及到关注点 2。不幸的是,答案没有引用任何官方文档/资源(并且并非所有人都同意)。此外,在那里,秘密库密钥不存在于 webapp 的源代码中(它在清单文件中),而在我们的例子中,秘密令牌 在源代码中。

问题:这种替代设置是否安全合理?

更新:我刚刚找到this answer,由一位看起来可信的用户撰写。答案是网络应用程序的用户将无法看到网络应用程序的代码,即使应用程序部署为“任何人,甚至是匿名的”。不过,此声明与“我所知道的”相对应。

【问题讨论】:

  • 我认为您不应该在脚本中编写令牌。不是因为安全问题,因为用户无法看到图书馆,而是因为它有一个过期时间。您应该尝试通过代码生成它。 This 可能会对您有所帮助。还有this
  • @Jescanellas 感谢您的评论。回复:“用户无法看到图书馆”;我假设您所说的库是指“Google Apps 脚本文件”,并且我假设您的意思是甚至无法检查与 webapp 对应的文件(并且希望也无法调试等)。这对我来说是很有价值的信息,你可能有这方面的消息来源吗?
  • Re: "你应该尝试通过代码生成它";请注意,我的设置并不典型,因为服务器通常会向用户询问令牌(涉及用户的交互),服务器可以使用令牌访问用户数据。你的first link 似乎是典型的情况。似乎StateTokenBuilder(您的第二个链接)旨在帮助进行典型设置...
  • ... 在我的设置中,服务器/后端/特权用户不需要令牌来访问用户数据,而是“作为用户”运行的 webapp 脚本告诉特权用户运行一个函数,它需要一个与特权用户关联的令牌。假设我们真的需要一个我们不想与用户共享的秘密,无论是令牌本身还是生成它的东西(如刷新令牌),我的困难是代表用户执行的脚本只能访问用户可用的信息,除了脚本的来源(或其他东西)。
  • 感谢您指出令牌过期是一个问题。我没有考虑那么多。如果我们将刷新令牌硬编码在 web 应用程序中,也许这仍然可以工作。同样,我很想知道这是否合理,或者存在哪些替代方案(如果有的话)。也许更合理的事情是让google cloud function 依次调用 api 可执行文件,但我已经超出了我的深度。

标签: security google-apps-script google-apps-script-api


【解决方案1】:

在大多数情况下,向网络应用发出请求可能更明智,而不是使用 API 可执行文件。可以向 Web 应用程序发出 get 或 post 请求,使 Web 应用程序知道谁在发出请求(即 Session.getActiveUser 在 Web 应用程序中工作)。

有关详细信息,请参阅此处(我的其他答案):https://stackoverflow.com/a/59428929/11873333

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-04
    • 2012-07-26
    • 2020-11-28
    • 2013-05-05
    • 2019-10-31
    • 2016-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多