每周获取最新的 Wordpress 资源

WordPress Nonce 是什么以及如何使用

Nonce 是 WordPress 安全的一个重要组成部分,但是 Nonce 经常会被误解以及误用。它们是授权一个 HTTP 请求到您的网站的一个关键部分,用来保证你的代码安全。

在这篇文章中,您将了解什么是 nonce,一个 WordPress nonce 是什么,它们是如何能够防御某些类型的攻击,还有他们无法防御的攻击类型,以及如何使用它们。

什么是 WordPress Nonce

Nonce 是加密散列,用来验证是否是正确的人或客户端所发送的请求。因为 nonce 是使用一个加密散列算法(例如 md5,sha1,sha2)和某种形式的秘密数据构造的,一般来说不太可能创建一个假的 nonce。

nonce 这个单词意思是:仅使用一次的数字。nonce 安全性的一个关键特性就是一次性使用。即使你拦截获得了一个有效的 nonce,一旦它被使用了,就无法再次使用。这个使得 nonce 对于重复攻击很有效。

就是说,WordPress nonce,并不是真正的 nonce,因为它可以在某段时间内一直有效,可以通过 nonce_life(详见Code Reference) 这个 filter 来定义它从创建开始的时效。这个意味着从技术上讲 WordPress nonce 可以使用不止一次,但仅限这个定义的时间段里。这个是需要谨记在心的区别。

跨站点请求伪造

我们经常认为我们的 WordPress 站点仅仅通过填写表单(如结账表单,文章编辑器,用户个人资料编辑器等等),然后点击提交来接受数据。但是那个仅仅是向一个站点发送 HTTP 请求的许多方法中的一个。

一旦一个表单的结构被摸清,然后就可以写一个脚本来模仿向这个表单发送请求。利用此漏洞来进行攻击的一种方式就是:在另外一个站点放上此表单的假版本,然后提交回原站点,来插入恶意数据。

这个就是一个跨站点请求伪造(CSRF)的攻击例子。它很大程度上可以通过使用 nonce 来避免。即使表单保持一模一样,然而 nonce 字段的值无法猜到。

每个发送给 WordPress 站点的请求,一个选项表单,一个针对 admin-ajax 的请求,Wordpress REST API,或者其他任何可以在站外发起的请求,都应该通过 nonce 来保护。

Nonce 只是整个系统的一部分

需要记住的是:仅验证一个 nonce,对于确定发送的请求是否经过授权是不够的。对于任何一个请求,权限的检验都是必要的。思考下面3个在 WordPress 插件中使用 admin-ajax 保存选项的例子:

<?php
add_action( 'wp_ajax_save_weibo', function(){
    if( isset( $_POST[ 'weibo' ] ) ){
        update_option( 'weibo', strip_tags( $_POST[ 'weibo' ] ) );
    }
});
 
add_action( 'wp_ajax_save_weibo', function(){
    if( current_user_can( 'mange_options' ) && isset( $_POST[ 'weibo' ] ) ){
        update_option( 'weibo', strip_tags( $_POST[ 'weibo' ] ) );
    }
});
 
add_action( 'wp_ajax_save_weibo', function(){
    if( current_user_can( 'mange_options' ) && isset( $_POST[ 'weibo-save-nonce' ],  $_POST[ 'weibo' ] ) && wp_verify_nonce( $_POST[ 'weibo-save-nonce' ], 'weibo-save-nonce' ) ){
        update_option( 'weibo', strip_tags( $_POST[ 'weibo' ] ) );
    }
});
?>

第一个例子允许任何拥有有效 cookie 的任何角色的用户来更新这个选项。如果你在 WordPress 站点使用这个代码,而我注册为一个订阅者,我可以登录到这个网站,获得我的 cookie,然后就可以使用浏览器控制台或者在我的 terminal 中使用 cURL 来修改这个选项。这是非常不安全的做法。

第二个例子会好一些,但是仍然不安全。这个代码中没有 nonce,但是它正确的检查了当前用户的权限。没有 nonce,正如我们前面讲的会受到跨站点请求伪造的攻击影响。这段代码就是钓鱼攻击网站的邀请函啊。

第三个例子增加了一个 nonce,这是正确的做法。如果我有个管理员 cookie 设置,同时我轻易被钓鱼网站欺骗了,这时候 nonce 将会起作用,让它通过不了,也就不会造成任何破坏。

Nonce 配合着身份验证一起工作,这样就无法跳过这一个或者另一个验证了。

使用 Nonce

WordPress 有着一系列的函数来和 nonce 配合工作。其中两个最重要的函数是 wp_create_nonce()wp_verify_nonce。都可以为动作执行(action)传入可选参数。你应当始终为你的请求设置唯一的动作执行(action)。这意味着你的 nonce 不可以用来重复验证另外一种类型的请求。

对于 nonce 在表单中使用,有一个助手函数(helper function)叫 wp_nonce_field(),可以用来创建一个 nonce 隐藏字段。下面这个表单可以和上面例子配合:

<form id="weibo-form">
    <label for="weibo-name">
        <?php esc_html_e( 'Weibo', 'text-domain' ); ?>
    </label>
    <input type="text" id="weibo-name" value="<?php echo esc_attr( get_option( 'weibo', '')  ); ?>" />
    <?php
        wp_nonce_field( 'weibo-save-nonce' );
        submit_button( __( 'Save', 'text-domain' ) );
    ?>
</form>
<script>
    jQuery( document ).ready(function($){
        $( '#weibo-form' ).on( 'click', function(e){
            $.post( ajaxurl, {
                'weibo-save-nonce' : $( '#_wpnonce' ).val(),
                weibo: $( '#weibo-name')
            })
        });
    });
</script>

这个将会用在只有管理员可以看到的菜单页面。因此 nonce 在被使用输出到屏幕显示的时候,只有管理员可以看到。在 admin-ajax 的回调函数中,nonce 验证和权限验证,结合 WordPress 对用户 cookie 的验证,一起来保证安全。

在这个例子中,我们使用了 AJAX 来提交表单,但是对于同步 HTTP 请求,这个过程是一样的。

现在就开始使用 Nonce

这就是关于 nonce 的一切了。为了提高 WordPress 网站的安全性,记住,无论如何都要使用 Nonce。

在我总结之前,还有另外两个观点需要说的是:

关于 Nonce 有一个重要的事情需要谨记在心的是,nonce 其中的一个组成部分就是当前用户的 ID,如果没有登录就是 0。这个意味着 nonce 在用户之间不可分享。这个可能会让人产生困惑,就是如果 nonce 在用户身份验证之前验证,那么正确的 nonce 将会无效。当一个 nonce 伴随着 WordPress REST API nonce 用来验证 cookie 身份验证被使用时,这就是一个会发生的问题。

另外一个重要的事情需要记住的是,nonce 会受到 PHP 计时攻击的影响。这就是为什么 WordPress 用户需要故意使用低效率的函数 hash_equals() 替代简单高效的字符串比较。你可能产生过通过生成一个期望的值然后用字符串比较来验证一个 nonce 的念头。然而,我建议你不要尝试和优化 nonce 验证的过程。

就这么多,仅仅简单地介绍了如何使用 nonce。我希望通过这篇文章你可以看到 nonce 是多么的简单,以及对于保证你的代码和站点安全是多么的重要。

You May Also Like

About the Author: ted

发表评论

电子邮件地址不会被公开。 必填项已用*标注