function CheckURL() {
$serverName = $_SERVER['SERVER_NAME'];
$referer = $_SERVER['HTTP_REFERER'] ?? '';
// 解析 referer 主機部分
$urlParts = parse_url($referer);
$refHost = $urlParts['host'] ?? '';
if (strcasecmp($refHost, $serverName) !== 0) {
die('警告!檢測到站外提交,請求被攔截。');
}
}
<form method="post" action="/vote">
<input type="hidden" name="token" value="= generate_csrf_token() ?>">
<input type="hidden" name="item_id" value="123">
<button type="submit">投票</button>
</form>
服務端驗證 $_POST['token'] 有效性(Session/Redis 存儲、一次性、過期時間)。
// 原生 XMLHttpRequest 封裝
function createXHR() {
if (window.XMLHttpRequest) return new XMLHttpRequest();
if (window.ActiveXObject) {
const versions = ['MSXML2.XmlHttp.6.0', 'MSXML2.XmlHttp.3.0'];
for (const v of versions) {
try { return new ActiveXObject(v); } catch(e) {}
}
}
throw new Error('瀏覽器不支持 AJAX');
}
function ajaxPost(url, data = '') {
const xhr = createXHR();
xhr.open('POST', url, false); // 同步演示,生產用異步
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status !== 200) console.error('請求失敗');
};
xhr.send(data);
}
// 使用
ajaxPost('/vote', 'item_id=123&token=' + getTokenFromMeta());
X-CSRF-Token)Set-Cookie: session=...; SameSite=Strict 防攜帶 Cookie 跨站請求// 中間件/基類控制器統一攔截
protected function verifyRequest() {
if ($this->request->isPost()) {
// 1. CSRF Token
if (!hash_equals(session('csrf_token'), $this->request->post('token'))) {
$this->fail('Token 無效');
}
// 2. 可選 Referer
if (config('check_referer') && ! $this->checkReferer()) {
$this->fail('非法來源');
}
}
// 3. 刷新 Token(可選)
session('csrf_token', bin2hex(random_bytes(32)));
}
Referer 檢查不可靠,CSRF Token + SameSite Cookie 是現代 Web 防偽造提交的標準組合。AJAX 利用同源策略提升門檻,但不能替代服務端 Token 驗證。分層防禦才是王道。