【问题标题】:API calls from JavaScript to backend: Ensuring legitimacy without server-side code从 JavaScript 到后端的 API 调用:无需服务器端代码即可确保合法性
【发布时间】:2017-08-09 01:51:57
【问题描述】:

我想创建一个 Javascript 小部件,我的用户可以将其放在他们的网站上。 该小部件能够创建音频,这又会花费我的用户的钱。

为了便于说明,假设每次放置在我用户网站上的小部件由互联网上的任何人(即我的用户的用户)加载时,我都会向我的用户收取 1 美元的费用。

小部件是包裹在 HTML 音频播放器周围的 Javascript 代码。每次加载时,JS 代码都会向我的后端 API 发出请求,并在收到来自我的后端 API 的响应后,构建播放器。

图表:

我担心不是我的用户的人恶意使用。 假设某人获取了他们在属于我的一个用户的网站上找到的小部件源代码,并将其放在 他们的 网站上。因此,他们会使用我的服务,但不会为此付费。相反,我的实际用户会为此付费(假设我使用公共 API 密钥作为区分我的用户的一种方式)。

通常,这可以通过让服务器端库负责任何可能花钱的使用来防止。例如,我使用 Pusher 作为我的 WebSockets IaaS,每当我想发布消息时,我都必须在服务器端使用他们的 PHP SDK,同时使用私有和公共 API 密钥。

在我的用例中,必须没有服务器端库。

问题:如何确保我收到的 API 请求是合法的?

我考虑使用放置小部件的主机名作为合法性措施。在小部件设置期间,我可以要求我的用户将某些(子)域列入白名单并拒绝所有不符合条件的请求,但这很容易被例如自定义本地域或 CURL-精心设计的请求。

我知道这可能是不可能的。

【问题讨论】:

    标签: javascript api security widget


    【解决方案1】:

    您的问题似乎与客户端加密主题密切相关。在大多数情况下,答案是否定的,不可能。但是,在这种情况下,可以按照以下方式实现一些东西。如果您可以让您的客户安装一个插件(您将构建该插件),您可以在完成后加密您的 JS 代码,并让您的服务器提供此加密文件。通常,这不足之处在于,如果您要发送加密文件,则需要有一种方法让客户端对其进行解密。这将要求您还提供一个未加密的 JS 文件来进行解码,但是通过提供未加密的解码器,您可以撤销通过加密您的主 JS 文件获得的任何安全性(解密文件可以很容易地用于对您的加密方法进行逆向工程/只是直接为您的预期用户以外的人运行)。现在,这就是让这些 API 用户(以及通过服务器-客户端连接之外的方式与他们进行通信的能力)派上用场的地方。如果您构建了一个解密插件,并将其提供给 API 用户(您可以为每个用户颁发一个唯一的解密密钥,但是如果没有服务器访问权限,实现唯一的用户密钥将非常困难/不可能),那么该插件可以解密您提供的文件在他们的浏览器中,基本上保证只有您提供“密钥”的用户才能访问您的软件。但是,这种方法有一些注意事项。这意味着您足够信任您的用户,以至于他们不会分发插件(无论如何分发它都会违背他们的意愿,因为如果人们冒充他们可能会导致更高的费用)。这种方法可能还有其他一些安全问题,但是,我现在想不出它们。如果有任何想法,我会编辑这篇文章并添加它们。

    【讨论】:

    • 这是一个有趣的想法。今天我自己也想出了一些东西,所以我将在今天晚些时候发布它作为答案,希望你能发表你的意见。
    • 是的,我很想知道你的想法,当你发表你的想法时,我会留下我的想法!
    • 我刚刚发布了它。请随时查看。
    【解决方案2】:

    显然,我还没有足够的声誉来发表评论,因此该帖子... 但是针对您的帖子,我认为这种方法似乎比我建议的方法要好得多;我没有意识到你可以控制 API 对服务器的响应。

    我不太明白你指的是以下哪个:

    a) 向用户发送一个 JS 文件,其唯一目的是确定是否也应该发送播放器(即在到达时,它使用客户端的 API 密钥/url ping 服务器)然后 然后 em> 服务器将提供文件(在这种情况下,您的方法对我来说似乎是安全的,但其他人可能会发现它存在安全问题)。

    b) 发送带有 JS 的文件音频播放器,到达后判断 URL 和 API 密钥是否正确,然后让音频播放器正常运行(发送 API服务器的密钥以跟踪使用情况,而不是作为安全功能)。

    如果使用选项 b,这不会提高安全性。如果您的代码依赖于在客户端运行的安全性,并且安全系统是通过与代码相同的方式发送的,那么几乎无一例外,所设计的系统都是有缺陷的并且本质上是不安全的。

    我希望这会有所帮助,如果您不同意/有更多问题,请随时发表评论!

    【讨论】:

    • 感谢您的评论。我的意思是a)。所以是的,让 JS 使用目标 URL(这是加载小部件的当前 URL)向 API 后端发送参数,并让后端根据目标 URL 和白名单的交集确定是否应该满足请求(子)域。 TLDR 让服务器验证请求,而不是前端,是从中的收获。应该马上想到的。
    【解决方案3】:

    如何将以下参数从 JavaScript 小部件发送到 API 后端:

    • 公共 API 密钥(例如 bbbe3b259f881cfc796f468619eb9d
    • 当前网址(例如https://example.com/articles/chiang-mai-thailand-january-2016-june-2016

    我将使用 API 密钥作为区分 my 用户和当前 URL 的一种方式,以了解要创建哪个音频文件(我的小部件将基于 URL 创建一个音频文件) .

    此外,这很关键,我将在我的中心站点上让用户将他们的域和子域列入白名单,我的用户将在那里获得他们的小部件代码。

    这与 FB 对其集成所做的相同:

    因此,例如,如果我的后端 API 接收到上述示例 URL,并且用户已将小部件设置为仅允许属于 foo.combar.baz.com 的 URL,我将拒绝音频创建过程并显示一个错误。

    您认为这种方法有什么问题吗?

    【讨论】:

    • @Arthur-R 你怎么看?
    猜你喜欢
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 2011-08-15
    相关资源
    最近更新 更多