4

我正在构建一个 API,并且有一个关于如何跟踪/知道哪些域使用该调用的问题。

API 调用是用 PHP 构建的,不需要任何身份验证。用户很可能会在其服务器上的 AJAX 调用中使用 API。

例如,我提供 API PHP 文件的域称为 dev.yourmapper.com。域 www.metromapper.org 上的某个人构建了一个页面,该页面创建了一个 Google 地图,并使用 Ajax 调用我的文件以将我的数据覆盖在他们的地图上。

这是该示例:http ://www.metromapper.org/example/apitest.htm

(单击中心地图标记可查看适用于 yourmapper.com 脚本的所有 PHP 服务器变量的弹出窗口。)

请注意,如果您单击链接,HTTP_REFERER 可能会是“stackoverflow.com”(如果您剪切并粘贴链接,则为空)。我认为引用者将是 metromapper.org,因为该域在加载后调用 yourmapper.com 脚本,但显然不是。

底线:我可以使用什么方法来确定哪个域正在使用 Javascript 调用我的 yourmapper.com 脚本?如果需要,我可以使用 PHP 以外的其他语言。谢谢。

4

2 回答 2

4

“我认为引用者将是 metromapper.org,因为该域在加载后调用 yourmapper.com 脚本”

这实际上是不正确的。首先,您永远不应该依赖 HTTP_REFERER,因为它是大多数(不是所有)浏览器传递的自愿参数,并且很容易被欺骗。如果我愿意,我可以使用 CURL 发送您的网站请求,使其看起来像是推荐人是 whitehouse.gov。那里没有安全措施。

话虽如此。浏览器将该参数设置为将用户引至当前加载页面的页面。不是脚本。所以你看到你看到的结果的原因是因为用户通过 stackoverflow.com 上的链接被引用到 metromapper.org

最后,让我们进入多汁的部分。您正在使用 JS 在浏览器中编写代码。这很好,这绝对没有问题。但是你必须记住 JS 是开源的。所以人们可以(并且将)弄乱你的代码来玩你的 API 只是因为他们可以。话虽如此。您最好的选择可能是将站点的 url 与您的 JS api 中的请求一起传递。这是“跟踪”哪些网站正在使用您的脚本的最佳方式。您可以检查服务器端以确保 URL 已通过。这将阻止人们修改您的 API 以删除将其 URL 发送到您的服务器的位。但是,它不会阻止他们修改它以使用其他人的 url 或随机未注册的 URL 作为参数。

当然,您可以构建他们在服务器上运行的 PHP API。JS API 连接到 PHP API 并且 PHP API 是 zend-guard 编码的(或其他一些源代码保护代码系统),但是仍然会有人解码文件以返回您的源代码并与您混淆。当然,能够做到这一点的人要少得多,而普通用户宁愿按原样使用您的 API。然后,您还会遇到人们无法在无法运行编码 PHP 文件的服务器上运行您的 API 的问题。

最后,您必须确定所需的安全和身份验证级别,但由于您的 API 在客户端浏览器中以 JavaScript 运行,因此除了混淆之外几乎没有什么可用的。

我想说你最好的选择是让你的 JS 代码抓住当前页面的 URL 并将其与 API 请求一起发送。从那里您的服务器可以处理 URL 以获取根域和您要存储的任何其他信息。

如果您想防止人们“欺骗”对其他用户网站 url 的请求,您可以实现一个 PHP API,该 API 安装在用户服务器的某个位置。例如http://www.domain.com/my-app-name.php

所有 JS API 调用都应该通过该脚本。当用户下载您的 API 时,他们应该输入他们的网站 URL 和其他一些信息。您的系统会生成一个“密钥”并将其注入到脚本中,然后再打包以供下载。该密钥对其域有效,并用于使用比方说河豚或其他 2 路加密算法对进出您的 API 的所有传输进行编码。这样,当您的 API 收到来自他们的 PHP API 文件的请求时,您将获得发出请求的页面的 url,并使用只有您和该站点的管理员拥有的密钥进行编码。所以请求是这样的:metromapper.org/api?site=[url_encoded_pa​​ge_address]&req=[encrypted_request]

您的服务器使用页面 url 来确定应该使用什么密钥来解密数据。然后它解密数据。如果数据已损坏或未解密为您所期望的,那么这是一个无效请求,您应该退出,什么也不返回。

我建议使用 PHP 文件进行加密而不是将加密写入 JS 的原因是因为您不想让客户端(每个站点访问者)承担加密/解密的负担,而 PHP 会更快地处理它比起 JS,因为有一些库可以为您处理这些任务。

无论如何,这应该让您走上正确的轨道,以便能够跟踪和验证针对您的 API 对不同站点的请求。

于 2011-08-15T21:28:49.960 回答
2

您可以根据域名生成哈希,并让您的 API 用户在每个请求中发送域名和哈希。现在,由于您的 API 使用 PHP,您将在标题中的某处设置“Access-Control-Allow-Origin”。如果您在 PHP 中执行此操作,您可以尝试一下。下面的脚本是一个简单的实现示例,在调用方(使用您的 API 的域)上不需要 php。

调用方(无需 php):

<script type="text/javascript">
  function callA() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("GET", "//ajaxdomain.com/call.php?"+
                      "dom=www.callerdomain.com&"+
                      "key=41f8201df6cf1322cc192025cc6c5013",
               true);
    xhttp.onreadystatechange = function() {
      if(xhttp.readyState == 4 && xhttp.status == 200) {
        handleResponse(xhttp.responseText);
      }
    }
    xhttp.send();
  }
</script>

Ajax 服务器端 (PHP):

<?php
  if($_GET['key']==md5($_GET['dom']."Salt")) {
    header("Access-Control-Allow-Origin: http://".$_GET['dom']);
  }
?>

这样,如果调用来自恶意域,也会放置标头,但由于跨域异常,其余部分会反弹,因此不会给出任何结果。

出于代码空间的考虑,我在此示例中使用了 md5 哈希,但如果您愿意,可以使用更复杂的哈希。请注意,您应该(一如既往)对使用过的盐保密。

我在以下(子)域中在线放置了一个工作示例。页面完全相同。

cors1.serioushare.com - 仅适用于“CORS 1”按钮。
cors2.serioushare.com - 仅适用于“CORS 2”按钮。

于 2015-12-02T17:40:22.100 回答