You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 19:09:04