PHP和AJAX安全问题

28

我目前正在构建一个Web应用程序,其中使用jQuery的$.ajax函数将PHP文件加载到主文件中。但是,通过在地址栏中键入文件名,显然仍然可以访问PHP文件。

因此,我的问题是如何最好地使被'ajaxed'的PHP文件知道它包含在正确的页面中并且将正常运行,但如果以任何其他方式访问它(即使有人制作自己的网站并将我的PHP文件AJAX进去),则该文件应该显示"拒绝访问"或类似信息。

提前感谢

6个回答

59

经过大量谷歌搜索后得出的答案!

步骤1:为所有Web服务生成令牌系统:

生成令牌:

<?php
  session_start();
  $token = md5(rand(1000,9999)); //you can use any encryption
  $_SESSION['token'] = $token; //store it as session variable
?>

步骤2:在发送 Ajax 调用时使用它:

var form_data = {
  data: $("#data").val(), //your data being sent with ajax
  token:'<?php echo $token; ?>', //used token here.
  is_ajax: 1
};

$.ajax({
  type: "POST",
  url: 'yourajax_url_here',
  data: form_data,
  success: function(response)
  {
    //do further
  }
});

步骤三:现在,让我们使用以下方法保护ajax处理程序PHP文件:

session_start(); //most of people forget this while copy pasting code ;)
if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
  //Request identified as ajax request

  if(@isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER']=="http://yourdomain/ajaxurl")
  {
   //HTTP_REFERER verification
    if($_POST['token'] == $_SESSION['token']) {
      //do your ajax task
      //don't forget to use sql injection prevention here.
    }
    else {
      header('Location: http://yourdomain.com');
    }
  }
  else {
    header('Location: http://yourdomain.com');
  }
}
else {
  header('Location: http://yourdomain.com');
}

注意:对于嵌套的if..else感到抱歉,但它增加了可理解性。 您可以将所有三个简化为一个if else。安全性提高了85%!


$token = md5(rand(1000,9999)); 这一行代码导致我的本地 PHP 需要 20 秒才能重新加载页面。 - arlg
这会如何防止有人通过控制台发送调用?那是否具有相同的HTTP_REFERER? - dartanian300
1
在这种情况下,令牌是无用的,因为JS脚本(步骤2)可被用户读取。 - zeuf
@zeuf:令牌是由服务器在页面加载时“每次(每个请求)”生成的。所以这没关系。 - Hardik Thaker
@dartanian300:任何人都可以伪造HTTP调用。HTTP_REFERER可以被修改。为了更好的安全性,在处理任何事情之前,您可以添加用户会话检查。 - Hardik Thaker
2
@HardikThaker @zeuf 如果您担心令牌在JavaScript中,您可以在服务器端使用盐。例如:$randomNumber = rand(1000, 9999); $browserToken = hash("sha256", $randomNumber); $saltValue = "abc123456"; $serverToken = $browserToken . $saltValue; $serverToken = hash("sha256", $serverToken); $_SESSION["token"] = $serverToken; 然后在验证时,只需重新创建serverToken并验证它是否匹配即可。 - Nick Marden

11

引用类似讨论Eran Galperin的话:

As others have said, Ajax request can be emulated be creating the proper headers. If you want to have a basic check to see if the request is an Ajax request you can use:

if($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
 //Request identified as ajax request
}

However you should never base your security on this check. It will eliminate direct accesses to the page if that is what you need.

请考虑Jeremy Ruten的回答:

无法保证他们是通过AJAX访问的。 直接访问和AJAX访问都来自客户端,因此很容易被伪造。

你为什么要这样做呢?

如果是因为PHP代码不够安全,请使PHP代码更加安全。(例如,如果您的AJAX将用户ID传递给PHP文件,则在PHP文件中编写代码以确保该用户ID是正确的。)

在上面链接的讨论中还有更聪明的想法。


那么,有人应该如何使用XMLHttpRequest访问此页面呢?您是否了解同源策略? - rook
我了解同源策略。可以通过检查XMLHttpRequest来判断脚本是通过AJAX(即你自己的脚本)调用,还是有人在浏览器中输入了该地址。不过,从自己网站的Firbug控制台调用该脚本则是另一回事了。 - middus

5

为了安全连接ajax和php,需要采用一些方式。你可以使用

if(@isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER']=="http://yourdomain/ajaxurl")
{
 //Request identified as ajax request
}

不要忘记保护 PHP 文件,因为使用 cURL 可以欺骗标头。


2

2

在另一个域上运行的JavaScript无法访问您域上的任何页面,因为这违反了同源策略。攻击者需要利用XSS漏洞才能实现此目的。简而言之,您不需要担心此特定攻击,只需关注影响每个Web应用程序的相同老问题。


1

这并不简单,也可能根本没有方法可以完全做到。您可以在PHP文件中要求一些POST变量,并在AJAX请求中发送它们。这将保护您免受那些只需将URL粘贴到浏览器中的人的侵害。

没有人能从其他域AJAX您的站点(安全问题),但始终可以连接并直接发送HTTP请求,例如通过cURL。

     

您可以在cookie中创建一些令牌,这也可以从jquery请求中看到,但这种解决方案也可能被黑客攻击。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接