如何禁止直接通过URL调用PHP,仅允许JavaScript触发游戏分数保存?
解决方案:禁止直接URL调用WordPress AJAX分数保存接口
要防止用户直接构造URL调用admin-ajax.php?action=save&score=100&user=Username,你需要从请求合法性验证入手,结合WordPress自带安全机制和前端请求规范实现,具体步骤如下:
1. 强制使用POST请求
直接URL调用默认是GET请求,你可以在save_score()函数里先判断请求方法,只处理POST请求:
function save_score() { // 只接受POST请求 if ($_SERVER['REQUEST_METHOD'] !== 'POST') { wp_send_json_error(array('message' => '非法请求方式'), 403); wp_die(); } // 处理分数参数 $score = isset($_POST['score']) ? intval($_POST['score']) : 0; $user = isset($_POST['user']) ? sanitize_text_field($_POST['user']) : ''; // 分数保存逻辑... wp_send_json_success(array('message' => '分数保存成功')); wp_die(); } add_action('wp_ajax_save', 'save_score'); add_action('wp_ajax_nopriv_save', 'save_score'); // 允许未登录用户调用(按需开启)
同时修改前端JS,改用POST方式发送请求:
// 游戏完成后提交分数 function saveGameScore(score, username) { fetch('/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ action: 'save', score: score, user: username }) }) .then(response => response.json()) .then(data => { data.success ? console.log('分数保存成功') : console.error('保存失败:', data.data.message); }); }
2. 添加WordPress Nonce验证(核心安全措施)
WordPress的Nonce(一次性随机数)能有效防止CSRF攻击和伪造请求,步骤如下:
步骤1:前端页面生成Nonce
通过页面输出或脚本本地化传递Nonce到前端:
// 方法1:在页面底部输出Nonce function print_game_nonce() { $nonce = wp_create_nonce('game_score_save_nonce'); echo "<script>const gameSaveNonce = '$nonce';</script>"; } add_action('wp_footer', 'print_game_nonce'); // 方法2:通过wp_localize_script传递(适合注册过的JS脚本) function enqueue_game_scripts() { wp_enqueue_script('game-script', get_template_directory_uri() . '/js/game.js', array('jquery'), '1.0', true); wp_localize_script('game-script', 'GameData', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('game_score_save_nonce') )); } add_action('wp_enqueue_scripts', 'enqueue_game_scripts');
步骤2:前端请求携带Nonce
修改JS请求,带上Nonce参数:
// 用wp_localize_script传递的情况 function saveGameScore(score, username) { fetch(GameData.ajax_url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: new URLSearchParams({ action: 'save', score: score, user: username, _wpnonce: GameData.nonce // 携带Nonce }) }) .then(response => response.json()) .then(data => { // 处理响应逻辑 }); }
步骤3:后端验证Nonce
在save_score()函数开头添加Nonce验证:
function save_score() { // 验证请求方法 if ($_SERVER['REQUEST_METHOD'] !== 'POST') { wp_send_json_error(array('message' => '非法请求方式'), 403); wp_die(); } // 验证Nonce有效性 if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], 'game_score_save_nonce')) { wp_send_json_error(array('message' => '请求验证失败'), 403); wp_die(); } // 后续分数处理逻辑... }
3. 补充:验证请求来源(可选增强)
可以检查请求Referer头,确保请求来自你的网站:
function save_score() { // ...前面的验证逻辑 // 验证请求来源 $allowed_referer = home_url(); if (!isset($_SERVER['HTTP_REFERER']) || strpos($_SERVER['HTTP_REFERER'], $allowed_referer) === false) { wp_send_json_error(array('message' => '非法请求来源'), 403); wp_die(); } // 后续逻辑... }
注意:HTTP_REFERER可被篡改,仅作为补充验证,不能单独依赖。
4. 进阶:游戏会话状态验证
如果需要更高安全性,可以记录用户游戏会话:
- 游戏开始时,前端请求生成一个会话ID,后端存储并标记为「进行中」
- 游戏结束时,前端携带会话ID提交分数,后端验证会话ID存在且状态为「进行中」,验证通过后标记为「已完成」并保存分数
这种方式能彻底杜绝未游玩就提交分数的情况,但实现复杂度更高,适合对安全性要求极高的场景。
内容的提问来源于stack exchange,提问作者Darin H
相关产品推荐
相关产品推荐

