您的代码在某些微妙的方面是不正确的,但要了解为什么我们首先需要回到wordpress中的nonce以及它能保护什么。
根据常见定义,Nonce是一个仅使用一次的数字,用于对抗重播攻击。在重播攻击中,您只是重播事务(http请求),而不了解其组件以重做用户操作。一个简单的例子是,如果有人可以重播你的购物订单,并导致你在没有你参与的情况下订购更多相同的东西,这可能会导致糟糕的情况。您使用其他人的网络的典型情况(不确定SSL是否有帮助)。
人们还发现,nonce是避免CSRF 攻击,因为很难预测攻击者应该使用的URL/参数。
在wordpress中,重要性的顺序是颠倒的,首要的是打击CSRF攻击,而打击重播攻击只是次要的。这导致wordpress nonces是一个“每天唯一”的数字,而不是经典的“一次性”数字。
那么wordpress如何使用nonce来保护CSRF呢?它根据上下文生成nonce。您可以在wp_create_nonce
密码
function wp_create_nonce($action = -1) {
$user = wp_get_current_user();
$uid = (int) $user->ID;
if ( ! $uid ) {
/** This filter is documented in wp-includes/pluggable.php */
$uid = apply_filters( \'nonce_user_logged_out\', $uid, $action );
}
$token = wp_get_session_token();
$i = wp_nonce_tick();
return substr( wp_hash( $i . \'|\' . $action . \'|\' . $uid . \'|\' . $token, \'nonce\' ), -12, 10 );
}
上下文是操作名称、用户id和当前登录会话,这确保了将为不同的操作、不同的用户甚至同一用户的不同会话生成不同的nonce,因此,即使有人知道在使用自己的用户执行操作(比如删除帖子)时用于执行操作的nonce,他无法通过构造具有相同nonce的特殊URL来欺骗您删除帖子。
这是你的第一个错误(很多人都会这样做),那就是试图对未登录的用户应用nonce。如果没有用户上下文,整个nonce都是从操作派生的,“攻击者”可以共享相同的url,供未登录的用户(或机器人)使用。
How to test that your code works correctly in preventing CSRF? 如果它是一个简单的URL,请在以其他用户身份登录时尝试重新发送它。处理url本身包含nonce的请求更容易,但可能可以使用浏览器开发人员工具(更改身份验证cookie并重新发送)或curl/wget来完成。
您编写代码所缺乏的另一部分是针对某种重播攻击的保护。假设我知道你喜欢帖子X,我是否可以重新传输请求并使其看起来像你也喜欢帖子Y?现在我要做的就是改变post_id
请求的参数。
防止此类攻击的方法是action
nonce的一部分是动态的,并以某种方式包括重要参数,在您的情况下是post id。Core通常使用此类操作delete-post-{post_id}
这将确保为不同的帖子生成不同的nonce。
How to test? 使用浏览器开发人员工具,更改post id参数,以确保相同的nonce不能用于收藏不同的帖子。
For phpunit type of testing 您可能需要编写自己的nonce生成器来包装wordpress核心nonce函数,并检查它们是否为不同的用户、不同的会话、不同的操作和不同的密钥请求参数提供相同的nonce。