3

Can Wordpress Nonces be used to protect against Login CSRF? https://codex.wordpress.org/WordPress_Nonces

I glanced through the code for the function and it seems to only be using the User ID for verification, that means that the attacker and victim will have the same nonce? Is this really correct?

user82444
  • 31
  • 2
  • Why would you want CSRF protection on a login screen in the first place? I know there are security consultants that recommend this, but what's the attack vector here? – Jeroen Aug 08 '15 at 16:15
  • @Jeroen-ITNerdbox http://support.detectify.com/customer/portal/articles/1969819-login-csrf – user82444 Aug 08 '15 at 16:17
  • 1
    Yeah, I disagree with what's written there. There's no solution for human stupidity. – Jeroen Aug 08 '15 at 16:22

2 Answers2

3

Yes, Wordpress nonces can protect against login CSRF.

Wordpress nonces can be applied to URLs and also forms, like the login form:

To add a nonce to a form, call wp_nonce_field() specifying a string representing the action. By default wp_nonce_field() generates two hidden fields, one whose value is the nonce and one whose value is the current URL (the referrer), and it echoes the result. For example, this call:

wp_nonce_field( 'delete-comment_'.$comment_id );

might echo something like:

<input type="hidden" id="_wpnonce" name="_wpnonce" value="796c7766b1" />
<input type="hidden" name="_wp_http_referer" value="/wp-admin/edit-comments.php" />

Usually, nonces are created attached to a user that is logged in because it makes sense to protect users that are logged in. But login CSRF is special because it can be used to target logged out user by logging them in.

Looking through the wp_create_nonce code I can see that nonces are created for logged out users as well:

function wp_create_nonce($action = -1) {
    $user = wp_get_current_user();
    $uid = (int) $user->ID;

    if ( ! $uid ) {
        $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 );
}

Then use wp_verify_nonce to verify the nonce. It returns false if the nonce in invalid. Otherwise, returns an integer with the value of:

  • 1: if the nonce has been generated in the past 12 hours or less.
  • 2: if the nonce was generated between 12 and 24 hours ago.
Cristian Dobre
  • 9,797
  • 1
  • 30
  • 50
0

I glanced through the code for the function and it seems to only be using the User ID for verification, that means that the attacker and victim will have the same nonce? Is this really correct?

Looking at the code it can be observed that the session identifier is used as part of the nonce generation:

    $token = wp_get_session_token();
    $i = wp_nonce_tick();

    return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );

This ties the session token to the nonce, so if the form was submitted using the nonces from another session (e.g. the attacker's nonce), wp_verify_nonce would not match it up, protecting against login CSRF.

See this answer for more on this technique (with anonymous cookies section).

SilverlightFox
  • 33,408
  • 6
  • 67
  • 178