如何使用 PHP 检查请求是否是 AJAX 请求

我想检查服务器端,如果请求我的 php 页面是一个 Ajax 请求或不。

我看到了两种方法:

第一种方法: 在请求中发送一个 GET参数,告诉页面这是一个 AJAX 请求(= mypage.php?ajax)

返回文章页面

if(isset($_GET['ajax'])) {
//this is an ajax request, process data here.
}

第二种方法: 将头部设置为 xmlHttpRequest:

客户端 js:

xmlHttpRequestObject.open(“GET”,url,true);
xmlHttpRequestObject.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

返回文章页面

if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ) {
//request is ajax
}

事实上,这两种方式很容易被黑客攻击,所以检查我是否收到这样的 AJAX 请求是不安全的。

如何检查我是否收到一个 AJAX 请求?

144511 次浏览

要知道请求是通过 Ajax 发出的,没有万无一失的方法。您永远不能信任来自客户端的数据。您可以使用几种不同的方法,但是可以通过欺骗轻松地克服它们。

您可以尝试使用 $_SESSION变量来确保从浏览器发出请求。否则,可以通过数据库或文件[服务器端]发送请求。

为站点上包含当前页名的每个页面(实际页面不包括或 rpcs)设置一个会话变量,然后在 Ajax 调用中传递一个用 $_SERVER['SCRIPT_NAME'];加盐的 nonce

<?php
function create_nonce($optional_salt='')
{
return hash_hmac('sha256', session_id().$optional_salt, date("YmdG").'someSalt'.$_SERVER['REMOTE_ADDR']);
}
$_SESSION['current_page'] = $_SERVER['SCRIPT_NAME'];
?>


<form>
<input name="formNonce" id="formNonce" type="hidden" value="<?=create_nonce($_SERVER['SCRIPT_NAME']);?>">
<label class="form-group">
Login<br />
<input name="userName" id="userName" type="text" />
</label>
<label class="form-group">
Password<br />
<input name="userPassword" id="userPassword" type="password" />
</label>
<button type="button" class="btnLogin">Sign in</button>
</form>
<script type="text/javascript">
$("form.login button").on("click", function() {
authorize($("#userName").val(),$("#userPassword").val(),$("#formNonce").val());
});


function authorize (authUser, authPassword, authNonce) {
$.ajax({
type: "POST",
url: "/inc/rpc.php",
dataType: "json",
data: "userID="+authUser+"&password="+authPassword+"&nonce="+authNonce
})
.success(function( msg ) {
//some successful stuff
});
}
</script>

然后在 RPC 中,你正在调用测试,一旦你通过了测试,如果它是好的,那么你的 RPC 被合法调用的几率是相当大的:

<?php
function check_nonce($nonce, $optional_salt='')
{
$lasthour = date("G")-1<0 ? date('Ymd').'23' : date("YmdG")-1;
if (hash_hmac('sha256', session_id().$optional_salt, date("YmdG").'someSalt'.$_SERVER['REMOTE_ADDR']) == $nonce ||
hash_hmac('sha256', session_id().$optional_salt, $lasthour.'someSalt'.$_SERVER['REMOTE_ADDR']) == $nonce)
{
return true;
} else {
return false;
}
}


$ret = array();
header('Content-Type: application/json');
if (check_nonce($_POST['nonce'], $_SESSION['current_page']))
{
$ret['nonce_check'] = 'passed';
} else {
$ret['nonce_check'] = 'failed';
}
echo json_encode($ret);
exit;
?>

Edit: FYI the way I have it set the nonce is only good for a hour and change,so if they have not resh the page doing the ajax call in the last hour or 2 Ajax request will fall.

来自 存档教程的例子:

if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
{
exit;
}
continue;

这将检查 HTTP_X_REQUESTED_WITH参数是否为空,如果它等于 xmlhttprequest,那么它将从脚本退出。

$headers = apache_request_headers();
$is_ajax = (isset($headers['X-Requested-With']) && $headers['X-Requested-With'] == 'XMLHttpRequest');

这个函数用于 Yii PHP 框架检查 AJAX 调用。

public function isAjax() {
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest';
}

从 PHP7开始,使用 null 结合运算符的时间会更短:

$is_ajax = 'xmlhttprequest' == strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ?? '' );

尝试下面的代码片段

if(!empty($_SERVER['HTTP_X_REQUESTED_WITH'])
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
{
/* This is one ajax call */
}

尝试使用 HTTP _ SEC

  if (!array_key_exists("HTTP_SEC_FETCH_SITE",$_SERVER) || $_SERVER["HTTP_SEC_FETCH_SITE"] != "same-origin")
die(header("HTTP/1.1 404 Not Found"));
if (!array_key_exists("HTTP_SEC_FETCH_MODE",$_SERVER) || $_SERVER["HTTP_SEC_FETCH_MODE"] != "cors")
die(header("HTTP/1.1 404 Not Found"));
if (!array_key_exists("HTTP_SEC_FETCH_DEST",$_SERVER) || $_SERVER["HTTP_SEC_FETCH_DEST"] != "empty")
die(header("HTTP/1.1 404 Not Found"));