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.