跨站請求偽造(CSRF)是一種極具危害性且難以防範的攻擊手段。攻擊者可透過誘導使用者點擊偽造連結、或在不知情下提交隱藏表單,進而竄改資料、發送垃圾訊息、甚至刪除關鍵資料。常見攻擊形式包括:
業界通用的低成本防禦方式,是在所有涉及寫入操作的表單中植入一個隨機且頻繁變換的字串,並在後端驗證該字串。若該隨機串與當前使用者身份綁定,攻擊者將難以偽造請求。知名案例包括 Yahoo 表單中的 .crumb、Facebook 的 post_form_id 與 fb_dtsg。
以下實作一個可重複使用的 Crumb 類別,採用 HMAC-MD5 產生與驗證 Token,支援自訂有效期(預設 2 小時)與動作區隔:
<?php
class Crumb {
const SALT = 'your-secret-salt'; // 請替換為專屬密鑰
static $ttl = 7200; // Token 存活秒數
static public function challenge($data) {
return hash_hmac('md5', $data, self::SALT);
}
static public function issueCrumb($uid, $action = -1) {
$i = ceil(time() / self::$ttl);
return substr(self::challenge($i . $action . $uid), -12, 10);
}
static public function verifyCrumb($uid, $crumb, $action = -1) {
$i = ceil(time() / self::$ttl);
// 允許當前與前一個時間窗口,避免邊界失效
if (substr(self::challenge($i . $action . $uid), -12, 10) == $crumb ||
substr(self::challenge(($i - 1) . $action . $uid), -12, 10) == $crumb) {
return true;
}
return false;
}
}
?>
參數說明: $uid 為使用者唯一識別碼;$ttl 控制 Token 有效時間;$action 可區分不同業務操作(如刪除、發文)。
<form method="post" action="demo.php">
<input type="hidden" name="crumb" value="<?php echo Crumb::issueCrumb($uid)?>">
<input type="text" name="content">
<input type="submit">
</form>
<?php
if (Crumb::verifyCrumb($uid, $_POST['crumb'])) {
// Token 通過,執行正常業務流程
} else {
// Token 驗證失敗,拒絕請求並提示錯誤
}
?>
採用此模式可有效阻擋 CSRF 攻擊,且實作簡單、效能開銷極低。建議在專案中統一封裝為中介層或基礎控制器方法,確保所有寫入操作皆受保護。