通过AJAX调用的两个PHP函数间如何安全传递验证码
问题原因
- 第一个问题是WordPress默认不会主动启动PHP Session,两次AJAX请求属于不同的会话上下文,所以无法读取到跨请求的Session值。
- 第二个问题是
confirm_sms函数的逻辑错误:第一行的wp_send_json($_SESSION['real_sms_code'])执行后会直接终止请求,后续的校验逻辑完全不会运行。
方案1:修复Session方案
在functions.php顶部添加Session初始化代码,确保所有请求都能复用同一会话:
add_action('init', function() { if (!session_id()) { session_start(); } });
修复confirm_sms的逻辑顺序,删除提前输出的测试代码,额外补充验证码有效期、手机号绑定、使用后销毁的安全逻辑即可。
方案2:更适合WordPress的无Session方案(推荐)
直接使用WordPress原生的transient临时缓存机制存储验证码,不需要额外处理Session配置,天然支持集群部署、自动过期,也能规避Session同步、会话劫持的风险:
后端PHP代码修改
add_action( 'wp_ajax_confirm_sms', 'confirm_sms' ); add_action( 'wp_ajax_nopriv_confirm_sms', 'confirm_sms' ); // 支持未登录用户调用 function confirm_sms() { // 校验入参 $input_code = sanitize_text_field($_POST['code']); $phone = sanitize_text_field($_POST['phone']); if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { wp_send_json_error('手机号格式错误'); } // 读取存储的验证码 $code_key = 'sms_code_' . md5($phone . '_' . $_SERVER['REMOTE_ADDR']); $real_code = get_transient($code_key); if (!$real_code) { wp_send_json_error('验证码已过期,请重新发送'); } if ($input_code !== $real_code) { wp_send_json_error('验证码错误,请重试'); } // 验证通过后立即删除验证码,防止重放攻击 delete_transient($code_key); wp_send_json_success('验证通过'); } add_action( 'wp_ajax_send_sms', 'send_sms' ); add_action( 'wp_ajax_nopriv_send_sms', 'send_sms' ); // 支持未登录用户调用 function send_sms() { $phone = sanitize_text_field($_POST['phone']); // 手机号格式校验 if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { wp_send_json_error('手机号格式错误'); } // 发送频率限制,1分钟1次 $limit_key = 'sms_limit_' . md5($phone . '_' . $_SERVER['REMOTE_ADDR']); if (get_transient($limit_key)) { wp_send_json_error('请求过于频繁,请1分钟后再试'); } // 生成验证码,存储有效期5分钟 $code = strval(rand(100000, 999999)); $code_key = 'sms_code_' . md5($phone . '_' . $_SERVER['REMOTE_ADDR']); set_transient($code_key, $code, 300); set_transient($limit_key, 1, 60); // 这里替换为实际的短信发送接口,上线后删除返回验证码的测试逻辑 // wp_send_json($code); wp_send_json_success('验证码已发送,请查收'); }
前端JS代码修改
需要在check_sms请求中同时提交手机号,用于匹配对应的验证码:
function check_sms() { jQuery.post( ajax_object.ajax_url, { action: "confirm_sms", code: document.getElementById("fi").value, phone: document.getElementById("phone").value // 新增手机号参数 }, function( response ) { document.getElementById("res").textContent = response.data; } ); }
额外优化建议
- 不要将验证码明文返回给前端,哪怕是测试环境也要尽快移除该逻辑,避免被爬虫利用直接获取验证码绕过校验
- 可增加验证码错误次数限制,同一个手机号连续错误3次就锁定10分钟,防止暴力破解
- 正式上线前建议将transient存储接入Redis等对象缓存,大用户量下性能比默认的数据库存储更好
内容的提问来源于stack exchange,提问作者user9102437
相关产品推荐
相关产品推荐

