欢迎来到今天的WordPress安全小讲堂!今天我们要一起扒一扒WordPress里一个非常重要的小函数——check_ajax_referer()
。它就像AJAX请求的门卫,专门负责检查进来的客人(也就是AJAX请求)有没有携带正确的“通行证”(Nonce)。
准备好了吗?让我们开始吧!
一、什么是Nonce?为什么要用它?
首先,我们得搞清楚什么是Nonce。Nonce,全称是"Number used once",顾名思义,它是一个只能使用一次的随机数。在WordPress的世界里,它主要用来防止CSRF(Cross-Site Request Forgery)攻击。
想象一下,如果没有Nonce,坏人可以伪造一个AJAX请求,冒充你执行一些操作,比如删除你的文章,修改你的用户资料。这可太可怕了!
Nonce就像一个秘密的握手协议。只有知道这个秘密的人才能顺利通过验证。每次请求,这个秘密都是不同的,这样就大大提高了安全性。
二、check_ajax_referer()
的作用
check_ajax_referer()
的主要作用就是验证AJAX请求中携带的Nonce是否有效。如果Nonce有效,说明这个请求很可能是来自你的站点,而不是坏人伪造的。如果Nonce无效,那就果断拒绝,保护你的站点安全。
三、check_ajax_referer()
函数的源码剖析
让我们一起深入wp-includes/functions.php
,看看 check_ajax_referer()
的源码:
function check_ajax_referer( $action = -1, $query_arg = false, $die = true ) {
if ( -1 == $action ) {
_doing_it_wrong( __FUNCTION__, __( 'The action should always be named in check_ajax_referer().' ), '4.2.0' );
return false;
}
$result = wp_verify_nonce( $_REQUEST[ $query_arg ], $action );
if ( false === $result ) {
/**
* Fires when an Ajax request fails the nonce check.
*
* @since 2.5.0
*
* @param string $action The name of the action that failed.
* @param string $result Result of the nonce verification.
*/
do_action( 'wp_ajax_nopriv_nonce_mismatch', $action, $result );
do_action( 'wp_ajax_nonce_mismatch', $action, $result );
if ( $die ) {
wp_nonce_ays( $action );
exit;
} else {
return false;
}
}
return true;
}
这段代码看起来有点长,但其实逻辑很简单。我们来一步一步分析:
-
参数说明:
$action
(string, required): 一个唯一的字符串,用来标识这个Nonce。 这个$action
值应该和你生成Nonce时使用的$action
值保持一致。 否则,验证肯定会失败。$query_arg
(string|false, optional): Nonce值在$_REQUEST
数组中的键名。 默认值是false
,意味着函数会默认查找$_REQUEST['_wpnonce']
。$die
(bool, optional): 如果验证失败,是否立即停止脚本执行。 默认值是true
,表示立即停止。
-
检查
$action
是否设置:if ( -1 == $action ) { _doing_it_wrong( __FUNCTION__, __( 'The action should always be named in check_ajax_referer().' ), '4.2.0' ); return false; }
这段代码首先检查
$action
是否等于 -1。 如果是,说明你没有提供$action
参数,这是一个非常糟糕的习惯。_doing_it_wrong()
函数会触发一个警告,告诉你哪里出错了。 然后函数直接返回false
,表示验证失败。 永远不要忽略这个警告! -
验证 Nonce:
$result = wp_verify_nonce( $_REQUEST[ $query_arg ], $action );
这是最关键的一步。 它调用了
wp_verify_nonce()
函数来验证Nonce。wp_verify_nonce()
函数会检查$_REQUEST
数组中$query_arg
键对应的值是否是一个有效的Nonce,并且与$action
关联。 如果$query_arg
是false
,它会默认查找$_REQUEST['_wpnonce']
。wp_verify_nonce()
函数返回1
(Nonce 在有效期内),2
(Nonce 过期时间小于 12 小时), 或者false
(Nonce 无效)。 -
处理验证失败的情况:
if ( false === $result ) { /** * Fires when an Ajax request fails the nonce check. * * @since 2.5.0 * * @param string $action The name of the action that failed. * @param string $result Result of the nonce verification. */ do_action( 'wp_ajax_nopriv_nonce_mismatch', $action, $result ); do_action( 'wp_ajax_nonce_mismatch', $action, $result ); if ( $die ) { wp_nonce_ays( $action ); exit; } else { return false; } }
如果
wp_verify_nonce()
返回false
,说明Nonce无效。 这段代码会触发两个Action Hook:wp_ajax_nopriv_nonce_mismatch
和wp_ajax_nonce_mismatch
。 你可以使用这些Hook来记录日志,或者执行其他自定义操作。然后,它会检查
$die
参数的值。 如果$die
是true
(默认值),它会调用wp_nonce_ays()
函数,显示一个错误信息,并立即停止脚本执行。 如果$die
是false
,它会返回false
,表示验证失败,但不会停止脚本执行。 你可以根据自己的需要来设置$die
参数。 -
验证成功:
return true;
如果
wp_verify_nonce()
返回1
或2
,说明Nonce有效。 函数返回true
,表示验证成功。
四、如何使用 check_ajax_referer()
现在我们知道了 check_ajax_referer()
的工作原理,接下来看看如何使用它。
步骤 1: 生成 Nonce
首先,你需要在前端生成一个Nonce。 WordPress 提供了 wp_create_nonce()
函数来生成Nonce。
$nonce = wp_create_nonce( 'my_ajax_action' );
这里的 'my_ajax_action'
是 $action
参数,它必须是一个唯一的字符串。 你可以使用任何你喜欢的字符串,只要它能唯一标识你的AJAX请求。
步骤 2: 将 Nonce 传递给前端
你需要将生成的Nonce传递给前端,以便在AJAX请求中使用。 你可以使用 wp_localize_script()
函数来做到这一点。
wp_enqueue_script( 'my-ajax-script', get_template_directory_uri() . '/js/my-ajax-script.js', array( 'jquery' ), '1.0', true );
wp_localize_script( 'my-ajax-script', 'my_ajax_object', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => $nonce
) );
这段代码会将 ajax_url
和 nonce
传递给名为 my_ajax_object
的JavaScript对象。 然后在你的JavaScript代码中,你可以通过 my_ajax_object.ajax_url
和 my_ajax_object.nonce
来访问这些值。
步骤 3: 在 AJAX 请求中包含 Nonce
在你的JavaScript代码中,你需要将Nonce包含在AJAX请求中。
jQuery.ajax({
url: my_ajax_object.ajax_url,
type: 'POST',
data: {
action: 'my_ajax_action',
security: my_ajax_object.nonce,
// 其他数据
},
success: function(response) {
// 处理响应
}
});
这里,我们将Nonce作为 security
参数传递给AJAX请求。 action
参数的值必须与你在 add_action()
中使用的值相同。
步骤 4: 在服务器端验证 Nonce
在服务器端,你需要使用 check_ajax_referer()
函数来验证Nonce。
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', 'security' );
// 处理AJAX请求
$data = $_POST['data'];
$response = 'OK';
wp_send_json_success( $response );
}
在这里,我们使用 check_ajax_referer()
函数来验证Nonce。 'my_ajax_action'
是 $action
参数,'security'
是 $query_arg
参数,它指定了Nonce在 $_REQUEST
数组中的键名。
五、一些需要注意的地方
$action
的唯一性:$action
参数必须是唯一的。 如果你在多个AJAX请求中使用相同的$action
,可能会导致安全问题。- Nonce 的有效期: Nonce的有效期是12个小时。 这意味着,如果用户在12个小时内没有使用Nonce,它就会失效。 你可以使用
wp_nonce_tick()
函数来调整Nonce的有效期,但这通常不是一个好主意。 - 不要在
GET
请求中使用 Nonce: Nonce应该只在POST
请求中使用。 因为GET
请求的参数会显示在URL中,这可能会导致Nonce泄露。 - 始终验证 Nonce: 无论你的AJAX请求有多么简单,都应该始终验证Nonce。 这可以防止CSRF攻击。
- 错误处理: 如果Nonce验证失败,你应该采取适当的措施,例如显示错误信息,或者记录日志。
六、一个完整的例子
让我们来看一个完整的例子,演示如何使用 check_ajax_referer()
来保护你的AJAX请求。
PHP (functions.php 或插件文件中):
add_action( 'wp_enqueue_scripts', 'my_enqueue_ajax_script' );
function my_enqueue_ajax_script() {
wp_enqueue_script( 'my-ajax-script', get_template_directory_uri() . '/js/my-ajax-script.js', array( 'jquery' ), '1.0', true );
wp_localize_script( 'my-ajax-script', 'my_ajax_object', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'my_ajax_action' )
) );
}
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', 'security' );
$data = $_POST['data'];
$response = '你发送的数据是: ' . $data;
wp_send_json_success( $response );
}
JavaScript (my-ajax-script.js):
jQuery(document).ready(function($) {
$('#my-button').click(function() {
var data = $('#my-input').val();
$.ajax({
url: my_ajax_object.ajax_url,
type: 'POST',
data: {
action: 'my_ajax_action',
security: my_ajax_object.nonce,
data: data
},
success: function(response) {
$('#my-result').text(response.data);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('Error: ' + textStatus + ' - ' + errorThrown);
$('#my-result').text('发生了错误!');
}
});
});
});
HTML (在你的主题文件中):
<input type="text" id="my-input" value="Hello, World!">
<button id="my-button">发送数据</button>
<div id="my-result"></div>
在这个例子中,我们创建了一个简单的表单,包含一个输入框和一个按钮。 当用户点击按钮时,JavaScript代码会发送一个AJAX请求到服务器端,并将输入框中的数据传递过去。 服务器端会验证Nonce,然后返回一个包含接收到的数据的响应。 JavaScript代码会将响应显示在 my-result
div中。
七、总结
check_ajax_referer()
是一个非常重要的函数,它可以帮助你保护你的WordPress站点免受CSRF攻击。 通过理解它的工作原理,并正确地使用它,你可以大大提高你的站点的安全性。
记住,安全是一个持续的过程,而不是一个一次性的任务。 所以,请务必时刻关注你的站点的安全性,并采取适当的措施来保护它。
希望今天的讲座对你有所帮助! 下次再见!