通过 AJAX 获取在您的服务器上调用 PHP 文件的域
Posted
技术标签:
【中文标题】通过 AJAX 获取在您的服务器上调用 PHP 文件的域【英文标题】:Getting the domain that calls an PHP file on your server through AJAX 【发布时间】:2011-10-20 06:40:02 【问题描述】:我正在构建一个 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 可能会是“***.com”(如果您剪切并粘贴链接,则为空)。我认为引用者将是 metromapper.org,因为该域在加载后调用 yourmapper.com 脚本,但显然不是。
底线:我可以使用什么方法来确定哪个域正在使用 javascript 调用我的 yourmapper.com 脚本?如果需要,我可以使用 PHP 以外的其他语言。谢谢。
【问题讨论】:
从某人刚刚留下的评论中,他们建议使用 REMOTE_HOST 和 REMOTE_ADDR,您可以在标记弹出窗口中看到。原来这是 Google 的 IP 地址,这是我的 yourmapper.com 数据在被 Google 提供之前所在的位置。 whatismyipaddress.com/ip/74.125.75.3 所以可能无法获取原始页面的 IP/域.... 从上面不清楚你的API是从服务器调用还是从地图所在的网页调用(例如通过JSONP,绕过为页面提供服务的服务器)。如果是后者,你可能可以将 Javascript 所在页面的 URL(window.location
)附加到您的 ajax 调用中。
@chris-carson 我在 dev.yourmapper.com 的 API 可以从任何人的网页(如 metromapper.org)调用。 API 可以将数据作为 JSON 提供,但在这种情况下,它作为 KML 提供以直接覆盖在地图上。由于我无法控制其他人的 Javascript 代码,因此我无法强制他们将 window.location
添加到 KML 请求中。
【参考方案1】:
“我认为引用者应该是 metromapper.org,因为该域在加载后会调用 yourmapper.com 脚本”
这实际上是不正确的。首先,您永远不应该依赖 HTTP_REFERER,因为它是大多数(不是所有)浏览器传递的自愿参数,并且很容易被欺骗。如果我愿意,我可以使用 CURL 发送您的网站请求,使其看起来像是推荐人是 whitehouse.gov。那里没有安全措施。
话虽如此。浏览器将该参数设置为将用户引至当前加载页面的页面。不是脚本。所以你看到你看到的结果的原因是因为用户通过 ***.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 以获取根域和您要存储的任何其他信息。
如果您想防止人们“欺骗”对其他用户网站网址的请求,您可以实现一个 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_page_address]&req=[encrypted_request]
您的服务器使用页面 url 来确定应该使用什么密钥来解密数据。然后它解密数据。如果数据已损坏或未解密为您所期望的,那么这是一个无效的请求,您应该直接退出,不返回任何内容。
我建议使用 PHP 文件进行加密而不是将加密写入 JS 的原因是因为您不想让客户端(每个站点访问者)承担加密/解密的负担,而 PHP 将处理它比 JS 快得多,因为有一些库可以为您处理这些任务。
无论如何,这应该能让您走上正确的轨道,以便能够跟踪和验证针对您的 API 对不同网站的请求。
【讨论】:
感谢 cmets 和好主意。关于 HTTP_REFERER 是的,我知道它可以被欺骗,但我更关心在 90% 的情况下跟踪它,而不是关于安全或欺骗。 JS也是如此。我无法告诉点击 JSON API 调用的用户是否通过了域。我可以,但这是最后的手段。另外,这比 REFERER 更容易更改。但我认为这是最后的手段。我不能要求人们在他们的服务器上放置一个所有调用都通过的 PHP 文件。一方面,大多数服务器不使用 PHP,而且它也有点过于繁琐。 您的最后一个想法是最可能的解决方案:让他们生成一个加密密钥。但问题是,任何查看源代码的人都可以清楚地看到这个密钥(连同站点变量)。然后他们有人可以剪切和粘贴它。我想我可能只需要使用 REMOTE_HOST IP 地址,然后即时从中发现域。这并不能解决 KML 的 Google 服务器问题,所以我必须单独解决。 是的,关于密钥的建议是假设您在他们的服务器上使用 PHP 文件。因为密钥只会存储在纯文本服务器端,而不是所有访问者可见的 JS 代码中。使用密钥系统将是防止人们通过修改代码来使您收集的数据无效的唯一方法。因为它可以让您确定请求确实来自他们的站点(并且不是有人修改 JS 代码)。如果您有这种能力,您还可以在 JSP/ASP 中编写小 API 文件。这将使其得到更广泛的支持。【参考方案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”按钮。
【讨论】:
以上是关于通过 AJAX 获取在您的服务器上调用 PHP 文件的域的主要内容,如果未能解决你的问题,请参考以下文章
如果在您的服务器上启用了 PATH_INFO,请检查 PHP?