各位看官,今天咱们不聊风花雪月,就来扒一扒 WordPress 里的“神秘代码”——nonce,尤其是在 AJAX 请求里,这玩意儿可是个保安队长,时刻保护着咱们的数据安全。准备好了吗?咱们这就开讲!
一、Nonce 是个啥?为啥要用它?
想象一下,你家的门钥匙,如果谁都能复制一把,那还得了?Nonce 在 WordPress 里就扮演着类似的角色,但它更聪明,它是一把“一次性钥匙”,用过一次就失效了。
Nonce,全称 "Number used once",顾名思义,就是“用一次的数字”。它是一个随机字符串,主要用来防止 CSRF(Cross-Site Request Forgery,跨站请求伪造)攻击。CSRF 攻击简单来说,就是坏人冒充你,偷偷地替你干坏事,比如发帖子、改密码之类的。
不用 Nonce 的话,坏人就可以构造一个恶意链接,诱骗你点击,然后浏览器就会偷偷地向你的网站发送请求,执行一些你不希望的操作。有了 Nonce,坏人就没那么容易得逞了,因为他不知道这把“一次性钥匙”。
二、Nonce 在 AJAX 请求中的应用:保安队长上线!
在 WordPress 的 AJAX 请求中,Nonce 的作用更加重要。因为 AJAX 请求通常是在后台默默地进行的,用户很难察觉,所以更需要保护。
2.1 生成 Nonce:制作钥匙
首先,我们需要生成 Nonce。WordPress 提供了 wp_create_nonce() 函数来完成这个任务。
$nonce = wp_create_nonce( 'my_ajax_action' );
这里的 'my_ajax_action' 是一个动作名称(action),你可以随便起,但一定要有意义,方便你识别。这个动作名称会参与到 Nonce 的生成过程中,相当于给钥匙配了一把锁。
2.2 传递 Nonce:把钥匙交给 AJAX
生成 Nonce 之后,我们需要把它传递给 JavaScript,让 AJAX 请求可以带上这把钥匙。
wp_localize_script( 'my_script', 'my_ajax_object', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => $nonce,
) );
这段代码的意思是,把 ajax_url 和 nonce 这两个变量传递给名为 my_script 的 JavaScript 文件,并且把它们放在一个名为 my_ajax_object 的 JavaScript 对象里。
这样,在 JavaScript 文件里,我们就可以通过 my_ajax_object.ajax_url 和 my_ajax_object.nonce 来访问这两个变量了。
2.3 发送 AJAX 请求:带着钥匙去开门
有了 Nonce,我们就可以在 AJAX 请求中把它发送到服务器了。
jQuery.ajax({
url: my_ajax_object.ajax_url,
type: 'POST',
data: {
action: 'my_ajax_action',
nonce: my_ajax_object.nonce,
// 其他数据
},
success: function(response) {
// 处理响应
}
});
注意,这里我们把 Nonce 放在 data 里一起发送到服务器。action 参数也要和生成 Nonce 时使用的动作名称保持一致。
2.4 验证 Nonce:保安队长验明正身
服务器收到 AJAX 请求后,就需要验证 Nonce 的有效性了。WordPress 提供了 check_ajax_referer() 函数来完成这个任务。
add_action( 'wp_ajax_my_ajax_action', 'my_ajax_callback' ); // 登录用户
add_action( 'wp_ajax_nopriv_my_ajax_action', 'my_ajax_callback' ); // 未登录用户
function my_ajax_callback() {
check_ajax_referer( 'my_ajax_action', 'nonce' );
// 处理 AJAX 请求
wp_send_json_success( array( 'message' => '请求成功!' ) );
wp_die(); // 结束 AJAX 请求
}
这里的 check_ajax_referer( 'my_ajax_action', 'nonce' ) 函数会验证 Nonce 是否有效。第一个参数是动作名称,第二个参数是 Nonce 在 $_POST 或 $_GET 数组中的键名。如果 Nonce 无效,check_ajax_referer() 函数会直接退出,阻止恶意请求。
三、check_ajax_referer() 源码分析:扒开保安队长的外套
咱们现在来深入分析一下 check_ajax_referer() 函数的源码,看看它是如何验证 Nonce 的。
check_ajax_referer() 函数的定义如下:
function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
return wp_verify_nonce( $_REQUEST[ $query_arg ], $action, $die );
}
可以看到,check_ajax_referer() 函数实际上是调用了 wp_verify_nonce() 函数来验证 Nonce 的。它只是简单地从 $_REQUEST 数组中获取 Nonce 的值,然后传递给 wp_verify_nonce() 函数。
wp_verify_nonce() 函数的源码比较复杂,咱们来一步步分析:
function wp_verify_nonce( $nonce, $action = -1 ) {
$nonce = (string) $nonce;
$i = wp_nonce_tick();
// Nonce generated 0-12 hours ago
$expected = substr( wp_hash( $i . '|' . $action . '|' . get_current_user_id() . '|' . wp_get_session_token(), 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}
// Nonce generated 12-24 hours ago
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . get_current_user_id() . '|' . wp_get_session_token(), 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}
// Invalid nonce
return false;
}
这段代码做了以下几件事:
-
获取时间戳:
wp_nonce_tick()函数返回一个基于时间戳的数字,这个数字每 12 小时会更新一次。function wp_nonce_tick() { /** * Filters the lifespan of nonces. * * @since 3.5.0 * * @param int $lifespan Nonce lifespan in seconds. Default 12 hours. */ $lifespan = apply_filters( 'nonce_life', DAY_IN_SECONDS / 2 ); return ceil( time() / ( $lifespan / 2 ) ); }可以看到,默认情况下,
Nonce的有效期是 12 小时。wp_nonce_tick()函数返回的是当前时间戳除以 12 小时得到的结果,向上取整。 -
生成期望的
Nonce:wp_hash()函数使用md5算法对一个字符串进行哈希,然后取哈希值的后 10 位作为期望的Nonce。这个字符串由以下几个部分组成:$i:当前的时间戳。$action:动作名称。get_current_user_id():当前用户的 ID。wp_get_session_token():当前用户的会话令牌。
这些信息组合在一起,可以唯一地标识一个
Nonce。 -
比较
Nonce:hash_equals()函数用于比较用户传递的Nonce和期望的Nonce是否相等。hash_equals()函数可以防止时序攻击,保证比较的安全性。 -
检查过期
Nonce: 为了防止由于服务器时间和客户端时间不一致导致Nonce验证失败,wp_verify_nonce()函数还会检查前一个 12 小时生成的Nonce是否有效。
如果用户传递的 Nonce 和当前时间戳或前一个时间戳生成的 Nonce 相等,wp_verify_nonce() 函数就会返回 1 或 2,表示 Nonce 验证成功。否则,返回 false,表示 Nonce 验证失败。
四、总结:安全第一,Nonce 护航!
Nonce 机制是 WordPress 中非常重要的安全机制,它可以有效地防止 CSRF 攻击,保护用户的数据安全。在 AJAX 请求中,Nonce 的作用更加重要,因为 AJAX 请求通常是在后台默默地进行的,用户很难察觉。
| 步骤 | 说明 | 函数/代码 |
|---|---|---|
| 1. 生成 Nonce | 使用 wp_create_nonce() 函数生成 Nonce。 |
$nonce = wp_create_nonce( 'my_ajax_action' ); |
| 2. 传递 Nonce | 使用 wp_localize_script() 函数将 Nonce 传递给 JavaScript。 |
wp_localize_script( 'my_script', 'my_ajax_object', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => $nonce, ) ); |
| 3. 发送请求 | 在 AJAX 请求中将 Nonce 发送到服务器。 | jQuery.ajax({ url: my_ajax_object.ajax_url, type: 'POST', data: { action: 'my_ajax_action', nonce: my_ajax_object.nonce, // 其他数据 }, success: function(response) { // 处理响应 } }); |
| 4. 验证 Nonce | 使用 check_ajax_referer() 函数验证 Nonce 的有效性。 |
check_ajax_referer( 'my_ajax_action', 'nonce' ); |
wp_verify_nonce 源码 |
验证 Nonce 的核心函数,校验时间戳、动作名称、用户ID和会话令牌。 | function wp_verify_nonce( $nonce, $action = -1 ) { ... } |
在使用 Nonce 时,需要注意以下几点:
- 动作名称要唯一: 不同的
AJAX请求应该使用不同的动作名称,防止Nonce被滥用。 Nonce的有效期: 默认情况下,Nonce的有效期是 12 小时。你可以通过nonce_life过滤器来修改Nonce的有效期。Nonce的安全性:Nonce本身并不是绝对安全的,它只能防止 CSRF 攻击。如果你的网站存在 XSS 漏洞,攻击者仍然可以获取到Nonce,然后利用它来发起攻击。因此,除了使用Nonce之外,还需要采取其他安全措施,比如过滤用户输入、使用 HTTPS 等。
好了,今天的讲座就到这里。希望大家能够理解 Nonce 机制的原理和应用,并在自己的 WordPress 项目中合理地使用 Nonce,保护网站的数据安全!记住,安全无小事,咱们要时刻保持警惕!
下次有机会,咱们再聊聊 WordPress 的其他“神秘代码”,不见不散!