Entfernen des Benutzernamens aus dem Cookie 'wordpress_logged_in'

9

Ich arbeite mit einem Kunden mit einigen strengen Sicherheitsmaßnahmen. Nach einer Sicherheitsüberprüfung wurde uns mitgeteilt, dass der Benutzername im angemeldeten Cookie gespeichert ist, z

wordpress_logged_in[username]|[hash]

ist etwas, das entfernt werden muss. Da dies ein wesentlicher Bestandteil des Anmeldesystems ist, bin ich mir nicht sicher, wie ich es entfernen und die Sitzung trotzdem pflegen soll.

Phatskat
quelle

Antworten:

10

Kurze Einführung

Nach einem kurzen Blick in den WP-Quellcode habe ich eine Lösung gefunden ...

WordPress verwendet zwei Funktionen zum Setzen und Analysieren von Authentifizierungscookies:

  • wp_generate_auth_cookie
  • wp_parse_auth_cookie

Es gibt einen Filter wp_generate_auth_cookienamens, mit auth_cookiedem Sie wahrscheinlich den Inhalt von Cookies ändern können, aber es gibt keinen Filter darin wp_parse_auth_cookie, aber ...

Beide Funktionen sind in pluggable.php definiert. Dies bedeutet, dass Sie Ihre eigenen Implementierungen für sie schreiben und Standardimplementierungen überschreiben können.

Lösung

  1. Schreiben Sie Ihr eigenes Plugin (nennen wir es Better Auth Cookie)
  2. Implementieren Sie Ihre eigenen wp_generate_auth_cookieund wp_parse_auth_cookieFunktionen in diesem Plugin.
  3. Aktivieren Sie Ihr Plugin.

Meine Beispielimplementierung (stark basierend auf Originalversionen) dieser Funktionen finden Sie unten:

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;

Meine Version dieser Funktionen ersetzt user_logindurch user_id. Aber es sollte ein guter Anfang sein, um es in etwas noch Komplexeres zu ändern (dh benutzerspezifischen Hash oder so etwas).

Krzysiek Dróżdż
quelle
Gute Antwort. Obwohl ich bis zum letzten Tag meiner Kopfgeldperiode warten werde. :)
Anonymes Schnabeltier
Ich werde dies akzeptieren, obwohl ich es nicht testen werde, da ich diese Lösung nicht mehr benötige. Sie haben sich offensichtlich viel Mühe gegeben, um an die Wurzel des Systems zu graben. Ich schätze die Mühe :)
Phatskat
1
Obwohl dieser Ansatz gut ist, sollten Sie sich bewusst sein, dass er keinen Schutz mehr bietet. Der Benutzername ersetzt die Benutzer-ID, aber der Benutzername kann von der Benutzer-ID über eine Anfrage an abgerufen werden example.com?author=123, die eine kanonische Umleitung zu einer URL wie z example.com/author/john.
John Blackbourn
1
@ John bitte sorgfältig lesen. Ich habe erwähnt, dass Sie es einfacher machen können, einen zufälligen Hash in einem Cookie anstelle der Benutzer-ID zu speichern.
Krzysiek Dróżdż