各位攻城狮、程序媛们,早上好!今天咱们来聊聊WordPress里一个看似不起眼,实则关系到网站安全的重要函数:wp_verify_nonce()
。它就像网站的“门卫”,负责检查每一个请求,看看是不是“自己人”发的,防止坏人来搞事情。
Nonce 是什么?为什么要验证?
在深入wp_verify_nonce()
之前,我们需要先理解Nonce的概念。Nonce,全称"Number used Once",顾名思义,就是一个只用一次的数字。在WordPress中,Nonce就是一个随机生成的字符串,用于验证请求的真实性。
想象一下,你经营一家咖啡馆,熟客来买咖啡,你认得他们,直接给他们做就行。但如果来了个陌生人,你怎么确定他不是来白嫖的呢?你可以让他说出一个只有熟客才知道的“暗号”,这个“暗号”就是Nonce。
为什么要验证Nonce呢?因为互联网上有很多坏人,他们会伪造请求,比如冒充用户提交表单、删除文章等等。如果没有Nonce验证,他们就可以为所欲为,网站就完蛋了!
wp_verify_nonce()
的源码解析:一层层揭开它的面纱
wp_verify_nonce()
函数位于wp-includes/pluggable.php
文件中。我们来逐步分析它的源码,看看它是如何工作的。
function wp_verify_nonce( $nonce, $action = -1 ) {
$nonce = (string) $nonce; // 确保 nonce 是字符串
$action = (string) $action; // 确保 action 是字符串
$nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS ); // 获取 nonce 的有效时间,默认一天
$i = wp_nonce_tick(); // 获取 nonce 的 "时间片"
// Nonce generated 0-12 hours ago
$expected = substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}
// Nonce generated 12-24 hours ago
$expected = substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}
// Invalid nonce
return false;
}
让我们逐行解读:
-
类型转换:
$nonce = (string) $nonce;
和$action = (string) $action;
这两行代码确保传入的$nonce
和$action
参数都是字符串类型。这是一个良好的编程习惯,可以避免一些潜在的类型错误。 -
Nonce 有效期:
$nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS );
这行代码获取Nonce的有效期,默认是DAY_IN_SECONDS
,也就是一天。你可以通过nonce_life
过滤器来修改Nonce的有效期。想象一下,如果你的“暗号”永远有效,那坏人总有一天会猜到! -
时间片:
$i = wp_nonce_tick();
这行代码获取一个叫做“时间片”的东西。这个时间片是用来增加Nonce的安全性的。function wp_nonce_tick() { $nonce_life = apply_filters( 'nonce_life', DAY_IN_SECONDS ); return ceil( time() / ( $nonce_life / 2 ) ); }
wp_nonce_tick()
函数返回一个整数,表示当前的时间片。它将当前时间除以nonce_life / 2
(也就是Nonce有效期的一半),然后向上取整。这意味着,Nonce的有效期被分成了两个时间片。举个例子:如果Nonce的有效期是24小时,那么每12小时,
wp_nonce_tick()
的返回值就会加1。这样做的目的是为了让Nonce更难以被预测。 -
生成期望的 Nonce:
$expected = substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
这行代码才是Nonce验证的核心。它使用以下步骤生成一个期望的Nonce:
- 拼接: 将当前时间片
$i
和$action
拼接在一起。$action
参数是一个字符串,用来标识这个Nonce是用于什么操作的,比如"delete_post"、"edit_post"等等。 - 哈希: 使用
wp_hash()
函数对拼接后的字符串进行哈希。wp_hash()
函数使用WordPress的盐值(salt)来增加哈希的安全性。盐值是一些随机生成的字符串,存储在wp-config.php
文件中。 - 截取: 从哈希后的字符串中截取最后10位字符作为期望的Nonce。
- 拼接: 将当前时间片
-
比较:
if ( hash_equals( $expected, $nonce ) ) { return 1; }
这行代码使用hash_equals()
函数来比较用户提交的Nonce和期望的Nonce是否相等。hash_equals()
函数是一个安全字符串比较函数,可以防止时序攻击。如果相等,说明Nonce是有效的,函数返回1。 -
检查上一个时间片:
$expected = substr( wp_hash( ( $i - 1 ) . $action, 'nonce' ), -12, 10 ); if ( hash_equals( $expected, $nonce ) ) { return 2; }
这段代码检查用户提交的Nonce是否是上一个时间片生成的。这样做是为了处理一些时钟同步的问题。如果用户的时钟稍微慢了一点,导致他提交的请求的时间片比服务器的时间片慢1,那么这段代码可以保证他的请求仍然有效。
-
无效 Nonce: 如果用户提交的Nonce既不是当前时间片生成的,也不是上一个时间片生成的,那么说明Nonce是无效的,函数返回
false
。
wp_create_nonce()
:生成 Nonce 的幕后英雄
既然要验证Nonce,那就要先生成Nonce。WordPress提供了wp_create_nonce()
函数来生成Nonce。
function wp_create_nonce( $action = -1 ) {
$action = (string) $action;
$i = wp_nonce_tick();
return substr( wp_hash( $i . $action, 'nonce' ), -12, 10 );
}
这个函数的代码非常简单,和wp_verify_nonce()
函数生成期望的Nonce的代码几乎一样。它也是将当前时间片$i
和$action
拼接在一起,然后使用wp_hash()
函数进行哈希,最后截取最后10位字符作为Nonce。
如何在 WordPress 中使用 Nonce?
说了这么多,那么如何在WordPress中使用Nonce呢?
-
生成 Nonce: 使用
wp_create_nonce()
函数生成Nonce。通常在HTML表单中添加一个隐藏的输入框来存储Nonce。<input type="hidden" name="my_nonce" value="<?php echo wp_create_nonce( 'my_action' ); ?>">
这里的
my_action
是$action
参数,用来标识这个Nonce是用于什么操作的。 -
验证 Nonce: 在处理表单提交的PHP代码中,使用
wp_verify_nonce()
函数来验证Nonce。if ( ! isset( $_POST['my_nonce'] ) || ! wp_verify_nonce( $_POST['my_nonce'], 'my_action' ) ) { wp_die( '安全检查失败!' ); }
这段代码首先检查
$_POST
数组中是否存在my_nonce
字段,然后使用wp_verify_nonce()
函数来验证Nonce。如果验证失败,就使用wp_die()
函数来显示一个错误信息。
完整示例:一个简单的表单提交
下面是一个完整的示例,演示如何在WordPress中使用Nonce来保护表单提交:
HTML表单:
<form method="post" action="">
<label for="my_input">请输入内容:</label>
<input type="text" id="my_input" name="my_input">
<input type="hidden" name="my_nonce" value="<?php echo wp_create_nonce( 'my_form_action' ); ?>">
<input type="submit" value="提交">
</form>
PHP处理代码:
<?php
if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
if ( ! isset( $_POST['my_nonce'] ) || ! wp_verify_nonce( $_POST['my_nonce'], 'my_form_action' ) ) {
wp_die( '安全检查失败!' );
}
$my_input = sanitize_text_field( $_POST['my_input'] ); // 对用户输入进行安全处理
echo '<p>你输入的内容是:' . esc_html( $my_input ) . '</p>'; // 显示用户输入
}
?>
在这个示例中,my_form_action
是$action
参数,用来标识这个Nonce是用于保护这个表单的提交。
wp_nonce_url()
和 wp_nonce_field()
:便捷的 Nonce 工具
除了wp_create_nonce()
和wp_verify_nonce()
函数之外,WordPress还提供了两个便捷的Nonce工具:wp_nonce_url()
和wp_nonce_field()
。
-
wp_nonce_url()
: 这个函数可以在URL中添加Nonce。$url = wp_nonce_url( 'admin.php?page=my_page&action=delete', 'delete_my_item' ); echo '<a href="' . esc_url( $url ) . '">删除</a>';
这段代码会在URL中添加一个
_wpnonce
参数,用来存储Nonce。在处理delete
操作的PHP代码中,可以使用wp_verify_nonce()
函数来验证Nonce。 -
wp_nonce_field()
: 这个函数可以生成一个包含Nonce的隐藏的输入框。wp_nonce_field( 'my_form_action' );
这段代码会生成以下HTML代码:
<input type="hidden" id="_wpnonce" name="_wpnonce" value="生成的Nonce值"> <input type="hidden" name="_wp_http_referer" value="当前页面的URL">
除了Nonce之外,
wp_nonce_field()
函数还会生成一个_wp_http_referer
字段,用来存储当前页面的URL。这个字段可以用来在验证Nonce之后将用户重定向回之前的页面。
总结:Nonce 是 WordPress 安全的重要组成部分
Nonce是WordPress安全的重要组成部分,它可以有效地防止跨站请求伪造(CSRF)攻击。通过生成和验证Nonce,我们可以确保每一个请求都是由真正的用户发起的,而不是由恶意攻击者伪造的。
函数/方法 | 作用 |
---|---|
wp_create_nonce() |
生成 Nonce 值 |
wp_verify_nonce() |
验证 Nonce 值是否有效 |
wp_nonce_url() |
在 URL 中添加 Nonce 参数 |
wp_nonce_field() |
生成包含 Nonce 值的隐藏表单字段,通常用于表单提交,同时包含referer信息 |
wp_nonce_tick() |
返回一个基于时间片的整数,用于 Nonce 的生成和验证,增加安全性。 |
希望今天的讲座能够帮助大家更好地理解wp_verify_nonce()
函数的工作原理,并在实际开发中正确地使用Nonce来保护WordPress网站的安全。 记住,安全无小事,多一份防范,少一份风险!
现在,有没有什么问题呢? 欢迎大家提问!