Suppression du nom d'utilisateur du cookie «wordpress_logged_in»

9

Je travaille avec un client avec des mesures de sécurité strictes. Après avoir subi un examen de sécurité, nous avons été informés que le nom d'utilisateur stocké dans le cookie connecté, par exemple

wordpress_logged_in[username]|[hash]

est quelque chose qui doit être supprimé. Étant donné que cela fait partie intégrante du système de connexion, je ne sais pas comment le supprimer et continuer à maintenir la session.

phatskat
la source

Réponses:

10

Brève introduction

Après un rapide aperçu du code source de WP, je pense avoir trouvé une solution ...

WordPress utilise deux fonctions pour définir et analyser les cookies d'authentification:

  • wp_generate_auth_cookie
  • wp_parse_auth_cookie

Il y a un filtre wp_generate_auth_cookieappelé auth_cookieque vous pourriez probablement utiliser pour changer le contenu du cookie, mais il n'y a pas de filtre à l'intérieur wp_parse_auth_cookie, mais ...

Ces deux fonctions sont définies dans pluggable.php, ce qui signifie que vous pouvez écrire vos propres implémentations pour elles et écraser celles par défaut.

Solution

  1. Écrivez votre propre plugin (appelons-le Better Auth Cookie)
  2. Implémentez vos propres fonctions wp_generate_auth_cookieet wp_parse_auth_cookiefonctions à l'intérieur de ce plugin.
  3. Activez votre plugin.

Vous pouvez trouver mon exemple d'implémentation (basé fortement sur les versions originales) de ces fonctions ci-dessous:

if ( !function_exists('wp_generate_auth_cookie') ) :
/**
 * Generate authentication cookie contents.
 *
 * @since 2.5.0
 *
 * @param int $user_id User ID
 * @param int $expiration Cookie expiration in seconds
 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
 * @param string $token User's session token to use for this cookie
 * @return string Authentication cookie contents. Empty string if user does not exist.
 */
function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
    $user = get_userdata($user_id);
    if ( ! $user ) {
        return '';
    }

    if ( ! $token ) {
        $manager = WP_Session_Tokens::get_instance( $user_id );
        $token = $manager->create( $expiration );
    }

    $pass_frag = substr($user->user_pass, 8, 4);

    $key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );

    // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
    $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
    $hash = hash_hmac( $algo, $user->user_login . '|' . $expiration . '|' . $token, $key );

    $cookie = $user_id . '|' . $expiration . '|' . $token . '|' . $hash;

    /**
     * Filter the authentication cookie.
     *
     * @since 2.5.0
     *
     * @param string $cookie     Authentication cookie.
     * @param int    $user_id    User ID.
     * @param int    $expiration Authentication cookie expiration in seconds.
     * @param string $scheme     Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'.
     * @param string $token      User's session token used.
     */
    return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme, $token );
}
endif;


if ( !function_exists('wp_parse_auth_cookie') ) :
/**
 * Parse a cookie into its components
 *
 * @since 2.7.0
 *
 * @param string $cookie
 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
 * @return array Authentication cookie components
 */
function wp_parse_auth_cookie($cookie = '', $scheme = '') {
    if ( empty($cookie) ) {
        switch ($scheme){
            case 'auth':
                $cookie_name = AUTH_COOKIE;
                break;
            case 'secure_auth':
                $cookie_name = SECURE_AUTH_COOKIE;
                break;
            case "logged_in":
                $cookie_name = LOGGED_IN_COOKIE;
                break;
            default:
                if ( is_ssl() ) {
                    $cookie_name = SECURE_AUTH_COOKIE;
                    $scheme = 'secure_auth';
                } else {
                    $cookie_name = AUTH_COOKIE;
                    $scheme = 'auth';
                }
        }

        if ( empty($_COOKIE[$cookie_name]) )
            return false;
        $cookie = $_COOKIE[$cookie_name];
    }

    $cookie_elements = explode('|', $cookie);
    if ( count( $cookie_elements ) !== 4 ) {
        return false;
    }

    list( $user_id, $expiration, $token, $hmac ) = $cookie_elements;

    $user = get_userdata($user_id);
    $username = ( ! $user ) ? '' : $user->user_login;

    return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' );
}
endif;

Ma version de ces fonctions remplace user_loginpar user_id. Mais cela devrait être un bon début pour le changer en quelque chose d'encore plus complexe (c'est-à-dire un hachage spécifique à l'utilisateur, ou quelque chose comme ça).

Krzysiek Dróżdż
la source
Bonne réponse. Bien que j'attende le dernier jour de ma période de primes. :)
Platypus anonyme
Je vais l'accepter, bien que je ne le testerai pas car je n'ai plus besoin de cette solution. Vous avez clairement mis beaucoup d'efforts pour creuser à la racine du système, j'apprécie l'effort :)
phatskat
1
Bien que cette approche soit bonne, vous devez savoir qu'elle n'offre plus de protection. Le nom d'utilisateur est substitué à l'ID utilisateur, mais le nom d'utilisateur peut être obtenu à partir de l'ID utilisateur via une demande à example.com?author=123, qui effectue une redirection canonique vers une URL telle que example.com/author/john.
John Blackbourn
1
@john lire attentivement s'il vous plaît. J'ai mentionné que vous pouvez facilement le rendre beaucoup plus sécurisé en stockant un hachage aléatoire dans un cookie au lieu de l'ID utilisateur.
Krzysiek Dróżdż