
本文介绍在不依赖 .htaccess 的前提下,通过会话校验、请求来源控制与 http 方法约束等 php 原生机制,有效阻止对 compute.php 等数据接口的非法直连访问,同时保障 a.php、b.php、c.php 中的合法 ajax 调用正常工作。
本文介绍在不依赖 .htaccess 的前提下,通过会话校验、请求来源控制与 http 方法约束等 php 原生机制,有效阻止对 compute.php 等数据接口的非法直连访问,同时保障 a.php、b.php、c.php 中的合法 ajax 调用正常工作。
在 Web 开发中,像 compute.php?number=800 这类用于 AJAX 数据交互的 PHP 接口,常面临一个典型安全困境:前端页面(如 a.php)需通过 jQuery .get() 动态调用它,但若用户直接在浏览器地址栏输入该 URL,服务端却无法区分“这是来自可信页面的合法请求”还是“恶意爬取或越权探测”。关键在于:HTTP 请求本身不携带“调用上下文”信息——浏览器发起的 AJAX 请求与手动访问,在服务端看来本质相同(同为 GET 请求),因此单靠请求方式或 URL 参数无法可靠鉴权。 必须引入主动式验证机制。
✅ 推荐方案:基于 Session 的一次性令牌(One-Time Token)
该方案轻量、可靠、不依赖服务器配置,且完全规避了 .htaccess 或 Web 服务器模块限制。
步骤一:在 a.php / b.php / c.php 中设置会话令牌
每个调用页面在加载时启动会话并写入临时标识:
<!-- a.php -->
<?php
session_start();
// 生成唯一、短期有效的令牌(可选:结合时间戳+随机数增强安全性)
$_SESSION['allowed_compute_call'] = bin2hex(random_bytes(16));
$_SESSION['compute_token_ttl'] = time() + 300; // 5分钟有效期
?>
<!DOCTYPE html>
<html>
<head><title>A Page</title></head>
<body>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$(document).ready(function() {
$.get('compute.php', {
number: 800,
token: '<?php echo $_SESSION['allowed_compute_call']; ?>'
}).done(function(res) {
console.log('Success:', res);
});
});
</script>
</body>
</html>✅ 优势:令牌仅存在于当前用户会话中,且带 TTL(生存期),即使被截获也极难复用。
立即学习“PHP免费学习笔记(深入)”;
Accessibility Review下载对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
步骤二:在 compute.php 中严格校验令牌
<?php
// compute.php —— 必须以 session_start() 开头
session_start();
// 1. 检查是否为 POST/GET 请求(推荐强制 POST,见后文)
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
die('Method Not Allowed');
}
// 2. 验证令牌是否存在且未过期
$token = $_GET['token'] ?? '';
if (
!isset($_SESSION['allowed_compute_call']) ||
!hash_equals($_SESSION['allowed_compute_call'], $token) || // 防时序攻击
!isset($_SESSION['compute_token_ttl']) ||
$_SESSION['compute_token_ttl'] < time()
) {
http_response_code(403);
die('Access Denied: Invalid or expired token');
}
// 3. 【关键】立即销毁令牌,实现“一次性”语义
unset($_SESSION['allowed_compute_call'], $_SESSION['compute_token_ttl']);
// 4. 执行业务逻辑(例如计算)
$number = (int)($_GET['number'] ?? 0);
$result = $number * 2; // 示例逻辑
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['success' => true, 'result' => $result]);
exit;⚠️ 重要注意事项:
- 必须使用 hash_equals() 进行令牌比对,防止时序攻击;
- unset() 销毁令牌是核心安全环节,确保同一令牌不可重复使用;
- 若项目已启用 session.auto_start=1,仍建议显式调用 session_start() 以明确控制流。
? 进阶加固:强制 POST + CSRF Token(更推荐)
GET 请求易被书签、日志、代理缓存,且参数暴露在 URL 中。将接口升级为 POST 可显著提升安全性,并天然兼容 CSRF 防护:
// 前端改用 POST(a.php 中)
$.post('compute.php', {
number: 800,
token: '<?php echo $_SESSION['allowed_compute_call']; ?>'
})// compute.php(POST 版本)
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit;
}
$token = $_POST['token'] ?? '';
// ... 后续校验逻辑同上(注意改为 $_POST)✅ 额外收益:配合 Access-Control-Allow-Methods: POST 响应头,可进一步约束跨域调用方式(适用于前后端分离场景)。
❌ 不可行方案辨析(避免踩坑)
- 仅检查 $_SERVER['HTTP_REFERER']:极易伪造,且现代浏览器/隐私插件常屏蔽 Referer,不可靠;
- 仅判断 $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest':AJAX 头可被任意客户端模拟,无实质防护;
- 仅用 in_array($_SERVER['REQUEST_METHOD'], ['GET']) 拦截非 GET:如资料所述,这只能终止 PHP 执行,但跨域预检(OPTIONS)和浏览器策略由响应头控制,无法替代真实鉴权。
✅ 总结:安全访问控制的核心原则
| 层级 | 措施 | 目的 |
|---|---|---|
| 会话层 | 一次性令牌 + TTL + 即时销毁 | 绑定调用上下文,防重放 |
| 传输层 | 强制 POST + JSON Content-Type | 避免 URL 泄露,提升协议健壮性 |
| 响应层 | 正确设置 Access-Control-Allow-Origin(如需跨域) | 兼容前端框架,同时避免 * 与 credentials 冲突 |
只要遵循“令牌生成→传递→校验→销毁”的闭环流程,即可在零配置改动的前提下,让 compute.php 对 a.php/b.php/c.php 完全开放,而对直接浏览器访问或脚本扫描彻底关闭——这才是面向真实生产环境的务实安全实践。



















