防止直接访问由ajax函数调用的文件

时间:2009-11-18 14:59:43

标签: php ajax

我从这样的ajax调用php代码:

ajaxRequest.open("GET", "func.php" + queryString, true);

由于这是一个获取请求,任何人都可以通过简单地检查标题来看到它。传递的数据不敏感,但可能会被滥用,因为获取参数名称也很简单。

如何阻止直接访问http://mysite/func.php但允许我的ajax页面访问它?

此外,我已尝试过解决方案posted here,但它对我不起作用 - 始终获取“直接访问未提交”消息。

12 个答案:

答案 0 :(得分:45)

大多数Ajax请求/框架应设置此特定标头,您可以使用它来过滤Ajax v非Ajax请求。我用它来帮助确定大量项目中的响应类型(json / html):

if( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && ( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) )
{
    // allow access....
} else {
    // ignore....
} 

编辑: 您可以在自己的Ajax请求中自行添加此项,并在javascript代码中添加以下内容:

var xhrobj = new XMLHttpRequest();
xhrobj.setRequestHeader("X-Requested-With", "XMLHttpRequest"); 

答案 1 :(得分:11)

我使用的是:PHP会话+每次执行请求时发送的哈希。这个哈希是使用服务器端的一些算法生成的

答案 2 :(得分:7)

嗯......您可以在会话启动时生成一次性密码,您可以将其存储在_SESSION中,并为您的ajax调用添加一个参数,该参数将重新传输此信息(类似于验证码)。它仅对该会话有效。

这可以保护您免受自动攻击,但是有权访问您网站的人仍然可以手动执行此操作,但它可能是设计更复杂内容的基础。

答案 3 :(得分:4)

我会质疑为什么你如此相信没有人应该能够直接访问该文件。您的第一个行动应该是假设人们可以直接访问该页面并围绕这种可能性采取行动。如果您仍然确信要关闭对此文件的访问权限,那么您应该知道您不能相信$_SERVER变量,因为$_SERVER的来源很难确定,并且标题的值可以被欺骗。在某些测试中,我发现这些标题($_SERVER['HTTP_X_REQUESTED_WITH']& $_SERVER['HTTP_X_REQUESTED_WITH'])也不可靠。

答案 4 :(得分:3)

此线程中建议查看标题的任何人在某种程度上都是错误的。请求中的任何内容(HTTP_REFERER,HTTP_X_REQUESTED_WITH)都可能被不完全无能的攻击者欺骗,包括共享机密[1]。

您无法阻止人们向您的网站发出HTTP请求。您要做的是确保用户在通过会话cookie向网站的某些敏感部分发出请求之前必须进行身份验证。如果用户发出未经身份验证的请求,请在此处停止并为其提供HTTP 403。

您的示例发出GET请求,因此我猜您关注请求的资源要求[2]。您可以对.htaccess规则中的HTTP_REFERER或HTTP_X_REQUESTED_WITH标头执行一些简单的完整性检查,以阻止针对明显虚假请求(或不会收听robots.txt的愚蠢搜索爬虫)生成新进程,但如果攻击者伪造那些,你要确保你的PHP进程尽早退出非经过身份验证的请求。

[1]这是客户端/服务器应用程序的基本问题之一。这就是为什么它不起作用:假设您有一种方法让您的客户端应用程序向服务器验证自己 - 无论是密码还是其他方法。应用程序所需的信息必须是应用程序可访问的(密码隐藏在某处,或其他任何地方)。但是因为它在用户的计算机上运行,​​这意味着他们也可以访问这些信息:他们所需要的只是查看源,二进制或应用程序与服务器之间的网络流量,最终他们会弄明白您的应用程序进行身份验证和复制的机制。也许他们甚至会复制它。也许他们会写一个聪明的黑客来让你的应用程序做繁重的工作(你总是可以向用户发送虚假的用户输入)。但无论如何,他们都获得了所需的所有信息,并且没有办法阻止他们拥有它也不会阻止你的应用程序拥有它。

[2]设计良好的应用程序中的GET请求没有副作用,因此没有人可以在服务器上进行更改。您的POST请求应始终使用session plus CSRF令牌进行身份验证,以便只有经过身份验证的用户才能调用它们。如果有人对此进行攻击,则表示他们拥有您的帐户,并且您想关闭该帐户。

答案 5 :(得分:2)

我解决了这个问题,准备了一个做三件事的检查功能

  1. 检查referer $ _SERVER [' HTTP_REFERER'];
  2. 检查http x请求$ _SERVER [' HTTP_X_REQUESTED_WITH'];
  3. 通过桥文件检查原点
  4. 如果全部三个通过,你成功看到ajax调用的php文件,如果只有一个失败你就得不到它

    已经解释了第1点和第2点,桥文件解决方案的工作原理如下:

    桥文件

    想象一下以下场景:

    通过ajax B.php

    A.php页面调用,您希望阻止直接访问B.php

    • 1)当加载A.php页面时,它会生成一个复杂的随机码
    • 2)将代码复制到不能直接访问的文件C.txt中 网页(httpd担保)
    • 3)同时此代码在渲染中清晰雕刻 A.php页面的html(例如作为正文的属性, es:

      数据桥=" ehfwiehfe5435ubf37bf3834i"

    • 4)这个雕刻代码从javascript中恢复并通过ajax发送 向B.php发送请求

    • 5)B.php页面获取代码并检查它是否存在于C.txt文件中
    • 6)如果代码匹配,则从C.txt和页面B.php中弹出代码 可以访问
    • 7)如果未发送代码(如果您尝试直接访问B 页面)或根本不匹配(如果您提供旧代码被困 或使用自定义代码进行技巧),B.php页面模具。

    通过这种方式,您只能通过父页面A生成的ajax调用访问B页面。 pageB.php的关键只能从pageA.php

    获得

答案 6 :(得分:1)

将以下代码放在由ajax调用的php文件的最顶层。它将执行ajax请求,但会" die" if直接从浏览器调用。

define('AJAX_REQUEST', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
if(!AJAX_REQUEST) {die();}

就个人而言,我选择在" die()"之后不输出任何内容作为额外的安全措施。这意味着我更喜欢向" intruder"显示一个空白页面,而不是给出提示,如" if"或"为什么"此页面受到保护。

答案 7 :(得分:0)

这样做没有意义。它不会增加任何实际的安全性。

所有表示通过Ajax发出请求的标头(如HTTP_X_REQUESTED_WITH)都可以在客户端伪造。

如果您的Ajax正在提供敏感数据或允许访问敏感操作,则需要添加适当的安全性,例如登录系统。

答案 8 :(得分:0)

我试过这个

1)在主php文件中(从中发送ajax请求)创建具有一些随机值的会话,如$_SESSION['random_value'] = 'code_that_creates_something_random';必须确定,该会话是在$.post之上创建的。

2)然后

$.post( "process_request.php", 
{ 
input_data:$(':input').serializeArray(),
random_value_to_check:'<?php echo htmlspecialchars( $_SESSION['random value'], ENT_QUOTES, "UTF-8"); ?>' 
}, function(result_of_processing) {
//do something with result (if necessary)
});

3)和process_request.php

if( isset($_POST['random_value_to_check']) and 
trim($_POST['random_value_to_check']) == trim($_SESSION['random value']) ){
//do what necessary
}

在我定义会话之前,然后使用会话值隐藏输入字段,然后使用ajax发送隐藏输入字段的值。但后来决定隐藏输入字段没有必要,因为可以不用它发送

答案 9 :(得分:0)

我有Edoardo解决方案的简化版本。

  1. 网页A创建一个随机字符串[token],并将具有该名称的文件保存在受保护文件夹中的磁盘上(例如,在Apache上使用带有Deny from all的.htaccess)。

  2. 页面A将[token]和AJAX请求一起传递给脚本B(在OP&#39; queryString中)。

  3. 脚本B检查[token]文件名是否存在,如果存在,则继续执行脚本的其余部分,否则退出。

  4. 您还需要设置一些清洁脚本,例如。与Cron一起,旧的代币不会累积在磁盘上。

  5. 使用脚本B立即删除[token]文件以限制多个请求也是一件好事。

    我不认为HTTP标头检查是必要的,因为它很容易被欺骗。

答案 10 :(得分:-1)

根据您的描述,我假设您正试图阻止彻底滥用,但不需要坚如磐石的解决方案。

由此,我建议使用cookies:

在使用AJAX的页面上只需setcookie(),并在func.php上检查$_COOKIE是否有正确的值。这将为您提供一些合理的保证,即最近有人调用func.php访问过您的网站。

如果您想获得更高级的话,您可以设置并验证唯一的会话ID(您可能已经这样做),以确保cookie不会被伪造或滥用。

答案 11 :(得分:-2)

我尝试了很多建议,没有人解决问题。最后我保护了php目标文件的参数,这是限制直接访问php文件的唯一方法。 **设置php文件并设置限制by.htaccess导致主Html页面中的Ajax连接失败。