通过AJAX获取调用服务器上PHP文件的域


Getting the domain that calls an PHP file on your server through AJAX

我正在构建一个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脚本,但显然不是。

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

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

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

话虽如此。浏览器将该参数设置为将用户引用到当前加载的页面的页面。没有脚本。所以你看到的结果是因为用户是通过stackoverflow.com

链接到metromapper。org的

最后,让我们进入有趣的部分。在浏览器中使用JS编写代码。这很好,绝对没有问题。但是你必须记住JS是开源的。所以人们可以(也将会)摆弄你的代码来玩你的API,因为他们可以这么做。话虽如此。最好的办法可能是在JS api中传递站点的url和请求。这是"跟踪"哪些网站在使用你的脚本的最好方法。您可以检查服务器端以确保传递了URL。这将防止人们修改您的API以删除将其URL发送到您的服务器的位。但是,它不会阻止他们修改它以使用其他人的url或随机未注册的url作为参数。

当然你可以构建一个PHP API在他们的服务器上运行。JS API连接到PHP API, PHP API是zend-guard编码的(或其他源代码保护代码系统),但仍然会有人解码文件,回到你的源代码,扰乱你。当然,能够做到这一点的人要少得多,而普通用户更愿意使用你的API。然后你也有问题,人们无法在服务器上运行你的API,而服务器不具备运行编码PHP文件的能力。

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

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

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

所有JS API调用都应该通过该脚本。当用户下载你的API时,他们应该输入他们的网站URL和其他一些信息。您的系统生成一个"密钥",并在打包脚本供他们下载之前将其注入脚本。该密钥对他们的域是有效的,并用于编码所有传输到/从你的API使用河豚或其他双向加密算法。这样,当您的API从他们的PHP API文件接收请求时,您将获得发出请求的页面的url,并使用只有您和该站点的管理员拥有的密钥进行编码。所以请求像这样通过:metromapper.org/api?site=[url_encoded_page_address]&req=[encrypted_request]

您的服务器使用页面url来确定应该使用哪个密钥来解密数据。然后对数据进行解密。如果数据已损坏或未解密为您期望的内容,则该请求无效,您应该退出,不返回任何内容。

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

无论如何,这应该使您能够根据您的API跟踪和验证不同站点的请求。

您可以基于域名生成散列,并让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'按钮