admin管理员组文章数量:1023018
Imagine the following scenario:
- John has an account on my website, but is currently not logged in.
- He clicks the "upvote" button on an article, but is redirected to the login page because only logged-in users can upvote.
- In the referral URL (to which John is redirected after login) the following parameters are passed:
action=upvote
article=1234
nonce=gibberish
. - After login, John is redirected to the referral URL which contains the "upvote" action.
- The nonce is now invalid because it was generated while not logged in.
The main problem here is that nonces are, from my understanding, generated with the user session. But after login, the session changes, thus making the nonce invalid.
Does WordPress have any way to handle cases like this?
Imagine the following scenario:
- John has an account on my website, but is currently not logged in.
- He clicks the "upvote" button on an article, but is redirected to the login page because only logged-in users can upvote.
- In the referral URL (to which John is redirected after login) the following parameters are passed:
action=upvote
article=1234
nonce=gibberish
. - After login, John is redirected to the referral URL which contains the "upvote" action.
- The nonce is now invalid because it was generated while not logged in.
The main problem here is that nonces are, from my understanding, generated with the user session. But after login, the session changes, thus making the nonce invalid.
Does WordPress have any way to handle cases like this?
Share Improve this question asked Apr 3, 2019 at 13:59 SwenSwen 1,4047 gold badges22 silver badges37 bronze badges 3- So you must trigger the upvote AFTER the user got logged in. Take the URL param you already have to accomplish this. – norman.lol Commented Apr 3, 2019 at 14:02
- 1 wp_verify_nonce and wp_create_nonce are 'pluggable', meaning you can declare your own versions in plugins to replace the core versions. You could e.g. separate logged in and logged out nonces, e.g. by prefixing them with 1 and 0 respectively, and have separate schemes to construct and validate them: use the current scheme for logged in users, but for logged out users e.g. use the IP address and a finer-grained timestamp in the hash so that logged out nonces have a much shorter timespan. – Rup Commented Apr 3, 2019 at 22:37
- 1 Then wp_verify_nonce can approve a not-logged-in nonce even after the user had logged in. But by far the simplest thing to do would be to redirect the user back to the page with the vote button, and have them press to vote again now that they're logged in. – Rup Commented Apr 3, 2019 at 22:39
1 Answer
Reset to default 3I went for the solution as suggested by @Rup in the comments. Replacing the two nonce functions, wp_create_nonce()
and wp_verify_nonce()
to prefix a nonce with a 1 or a 0 for logged-in and logged-out users respectively.
The logged out nonces work by IP rather than User ID and session Token. Thus, allowing for nonces to carry over after a login. As far as I can tell, this doesn't have any significant impact on security.
if ( ! function_exists( 'wp_create_nonce' ) ) {
/**
* Creates a cryptographic token tied to a specific action, user, user session,
* and window of time.
*
* @since 2.0.3
* @since 4.0.0 Session tokens were integrated with nonce creation
*
* @param string|int $action Scalar value to add context to the nonce.
* @return string The token.
*/
function wp_create_nonce( $action = -1 ) {
$user = wp_get_current_user();
$uid = (int) $user->ID;
$logged_in = '1-';
$token = wp_get_session_token();
$i = wp_nonce_tick();
if ( ! $uid ) {
// Prefix when logged-out nonce
$logged_in = '0-';
/** This filter is documented in wp-includes/pluggable.php */
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
// Use IP instead of user_id
$uid = $_SERVER['REMOTE_ADDR'];
$token = $_SERVER['REMOTE_ADDR'];
}
return $logged_in . substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
}
}
if ( ! function_exists( 'wp_verify_nonce' ) ) {
/**
* Verify that correct nonce was used with time limit.
*
* The user is given an amount of time to use the token, so therefore, since the
* UID and $action remain the same, the independent variable is the time.
*
* @since 2.0.3
*
* @param string $nonce Nonce that was used in the form to verify
* @param string|int $action Should give context to what is taking place and be the same when nonce was created.
* @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
* 0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
*/
function wp_verify_nonce( $nonce, $action = -1 ) {
$nonce = (string) $nonce;
$user = wp_get_current_user();
$uid = (int) $user->ID;
if ( ! $uid ) {
/**
* Filters whether the user who generated the nonce is logged out.
*
* @since 3.5.0
*
* @param int $uid ID of the nonce-owning user.
* @param string $action The nonce action.
*/
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
}
if ( empty( $nonce ) ) {
return false;
}
$token = wp_get_session_token();
$i = wp_nonce_tick();
// Check if nonce is for logged_in or logged_out ('1-' and '0-' respectively)
if ( substr( $nonce, 0, 2 ) == '0-' ) {
// Use IP instead of user_id and session token
$uid = $_SERVER[ 'REMOTE_ADDR' ];
$token = $_SERVER['REMOTE_ADDR'];
}
// Remove nonce prefix
$nonce = substr( $nonce, 2 );
// Nonce generated 0-12 hours ago
$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}
// Nonce generated 12-24 hours ago
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}
/**
* Fires when nonce verification fails.
*
* @since 4.4.0
*
* @param string $nonce The invalid nonce.
* @param string|int $action The nonce action.
* @param WP_User $user The current user object.
* @param string $token The user's session token.
*/
do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
// Invalid nonce
return false;
}
}
Imagine the following scenario:
- John has an account on my website, but is currently not logged in.
- He clicks the "upvote" button on an article, but is redirected to the login page because only logged-in users can upvote.
- In the referral URL (to which John is redirected after login) the following parameters are passed:
action=upvote
article=1234
nonce=gibberish
. - After login, John is redirected to the referral URL which contains the "upvote" action.
- The nonce is now invalid because it was generated while not logged in.
The main problem here is that nonces are, from my understanding, generated with the user session. But after login, the session changes, thus making the nonce invalid.
Does WordPress have any way to handle cases like this?
Imagine the following scenario:
- John has an account on my website, but is currently not logged in.
- He clicks the "upvote" button on an article, but is redirected to the login page because only logged-in users can upvote.
- In the referral URL (to which John is redirected after login) the following parameters are passed:
action=upvote
article=1234
nonce=gibberish
. - After login, John is redirected to the referral URL which contains the "upvote" action.
- The nonce is now invalid because it was generated while not logged in.
The main problem here is that nonces are, from my understanding, generated with the user session. But after login, the session changes, thus making the nonce invalid.
Does WordPress have any way to handle cases like this?
Share Improve this question asked Apr 3, 2019 at 13:59 SwenSwen 1,4047 gold badges22 silver badges37 bronze badges 3- So you must trigger the upvote AFTER the user got logged in. Take the URL param you already have to accomplish this. – norman.lol Commented Apr 3, 2019 at 14:02
- 1 wp_verify_nonce and wp_create_nonce are 'pluggable', meaning you can declare your own versions in plugins to replace the core versions. You could e.g. separate logged in and logged out nonces, e.g. by prefixing them with 1 and 0 respectively, and have separate schemes to construct and validate them: use the current scheme for logged in users, but for logged out users e.g. use the IP address and a finer-grained timestamp in the hash so that logged out nonces have a much shorter timespan. – Rup Commented Apr 3, 2019 at 22:37
- 1 Then wp_verify_nonce can approve a not-logged-in nonce even after the user had logged in. But by far the simplest thing to do would be to redirect the user back to the page with the vote button, and have them press to vote again now that they're logged in. – Rup Commented Apr 3, 2019 at 22:39
1 Answer
Reset to default 3I went for the solution as suggested by @Rup in the comments. Replacing the two nonce functions, wp_create_nonce()
and wp_verify_nonce()
to prefix a nonce with a 1 or a 0 for logged-in and logged-out users respectively.
The logged out nonces work by IP rather than User ID and session Token. Thus, allowing for nonces to carry over after a login. As far as I can tell, this doesn't have any significant impact on security.
if ( ! function_exists( 'wp_create_nonce' ) ) {
/**
* Creates a cryptographic token tied to a specific action, user, user session,
* and window of time.
*
* @since 2.0.3
* @since 4.0.0 Session tokens were integrated with nonce creation
*
* @param string|int $action Scalar value to add context to the nonce.
* @return string The token.
*/
function wp_create_nonce( $action = -1 ) {
$user = wp_get_current_user();
$uid = (int) $user->ID;
$logged_in = '1-';
$token = wp_get_session_token();
$i = wp_nonce_tick();
if ( ! $uid ) {
// Prefix when logged-out nonce
$logged_in = '0-';
/** This filter is documented in wp-includes/pluggable.php */
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
// Use IP instead of user_id
$uid = $_SERVER['REMOTE_ADDR'];
$token = $_SERVER['REMOTE_ADDR'];
}
return $logged_in . substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
}
}
if ( ! function_exists( 'wp_verify_nonce' ) ) {
/**
* Verify that correct nonce was used with time limit.
*
* The user is given an amount of time to use the token, so therefore, since the
* UID and $action remain the same, the independent variable is the time.
*
* @since 2.0.3
*
* @param string $nonce Nonce that was used in the form to verify
* @param string|int $action Should give context to what is taking place and be the same when nonce was created.
* @return false|int False if the nonce is invalid, 1 if the nonce is valid and generated between
* 0-12 hours ago, 2 if the nonce is valid and generated between 12-24 hours ago.
*/
function wp_verify_nonce( $nonce, $action = -1 ) {
$nonce = (string) $nonce;
$user = wp_get_current_user();
$uid = (int) $user->ID;
if ( ! $uid ) {
/**
* Filters whether the user who generated the nonce is logged out.
*
* @since 3.5.0
*
* @param int $uid ID of the nonce-owning user.
* @param string $action The nonce action.
*/
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
}
if ( empty( $nonce ) ) {
return false;
}
$token = wp_get_session_token();
$i = wp_nonce_tick();
// Check if nonce is for logged_in or logged_out ('1-' and '0-' respectively)
if ( substr( $nonce, 0, 2 ) == '0-' ) {
// Use IP instead of user_id and session token
$uid = $_SERVER[ 'REMOTE_ADDR' ];
$token = $_SERVER['REMOTE_ADDR'];
}
// Remove nonce prefix
$nonce = substr( $nonce, 2 );
// Nonce generated 0-12 hours ago
$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}
// Nonce generated 12-24 hours ago
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}
/**
* Fires when nonce verification fails.
*
* @since 4.4.0
*
* @param string $nonce The invalid nonce.
* @param string|int $action The nonce action.
* @param WP_User $user The current user object.
* @param string $token The user's session token.
*/
do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );
// Invalid nonce
return false;
}
}
本文标签: securityHandling nonces for actions from guests to loggedin users
版权声明:本文标题:security - Handling nonces for actions from guests to logged-in users 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745587778a2157702.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论