Make WordPress Core


Ignore:
Timestamp:
07/18/2014 09:12:05 AM (12 years ago)
Author:
nacin
Message:

Tie cookies and nonces to user sessions so they may be invalidated upon logout.

Sessions are stored in usermeta via WP_User_Meta_Session_Tokens, which extends the abstract WP_Session_Tokens class. Extending WP_Session_Tokens can allow for alternative storage, such as a separate table or Redis.

Introduces some simple APIs for session listing and destruction, such as wp_get_active_sessions() and wp_destroy_all_sessions().

This invalidates all existing authentication cookies, as a new segment (the session token) has been added to them.

props duck_, nacin, mdawaffe.
see #20276.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/pluggable.php

    r28939 r29221  
    587587 */
    588588function wp_logout() {
     589        wp_destroy_current_session();
    589590        wp_clear_auth_cookie();
    590591
     
    632633        $username = $cookie_elements['username'];
    633634        $hmac = $cookie_elements['hmac'];
     635        $token = $cookie_elements['token'];
    634636        $expired = $expiration = $cookie_elements['expiration'];
    635637
     
    667669        $pass_frag = substr($user->user_pass, 8, 4);
    668670
    669         $key = wp_hash($username . $pass_frag . '|' . $expiration, $scheme);
    670         $hash = hash_hmac('md5', $username . '|' . $expiration, $key);
    671 
    672         if ( hash_hmac( 'md5', $hmac, $key ) !== hash_hmac( 'md5', $hash, $key ) ) {
     671        $key = wp_hash( $username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
     672        $hash = hash_hmac( 'sha256', $username . '|' . $expiration . '|' . $token, $key );
     673
     674        if ( hash_hmac( 'sha256', $hmac, $key ) !== hash_hmac( 'sha256', $hash, $key ) ) {
    673675                /**
    674676                 * Fires if a bad authentication cookie hash is encountered.
     
    682684        }
    683685
    684         if ( $expiration < time() ) {// AJAX/POST grace period set above
     686        $manager = WP_Session_Tokens::get_instance( $user->ID );
     687        if ( ! $manager->verify_token( $token ) ) {
     688                do_action( 'auth_cookie_bad_session_token', $cookie_elements );
     689                return false;
     690        }
     691
     692        // AJAX/POST grace period set above
     693        if ( $expiration < time() ) {
    685694                $GLOBALS['login_grace_period'] = 1;
    686695        }
     
    709718 * @param int $expiration Cookie expiration in seconds
    710719 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
    711  * @return string Authentication cookie contents
    712  */
    713 function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
     720 * @param string $token User's session token to use for this cookie
     721 * @return string Authentication cookie contents. Empty string if user does not exist.
     722 */
     723function wp_generate_auth_cookie( $user_id, $expiration, $scheme = 'auth', $token = '' ) {
    714724        $user = get_userdata($user_id);
     725        if ( ! $user ) {
     726                return '';
     727        }
     728
     729        if ( ! $token ) {
     730                $manager = WP_Session_Tokens::get_instance( $user_id );
     731                $token = $manager->create_token( $expiration );
     732        }
    715733
    716734        $pass_frag = substr($user->user_pass, 8, 4);
    717735
    718         $key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
    719         $hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
    720 
    721         $cookie = $user->user_login . '|' . $expiration . '|' . $hash;
     736        $key = wp_hash( $user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme );
     737        $hash = hash_hmac( 'sha256', $user->user_login . '|' . $expiration . '|' . $token, $key );
     738
     739        $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
    722740
    723741        /**
     
    730748         * @param int    $expiration Authentication cookie expiration in seconds.
    731749         * @param string $scheme     Cookie scheme used. Accepts 'auth', 'secure_auth', or 'logged_in'.
    732          */
    733         return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme );
     750         * @param string $token      User's session token used.
     751         */
     752        return apply_filters( 'auth_cookie', $cookie, $user_id, $expiration, $scheme, $token );
    734753}
    735754endif;
     
    773792
    774793        $cookie_elements = explode('|', $cookie);
    775         if ( count($cookie_elements) != 3 )
     794        if ( count( $cookie_elements ) !== 4 ) {
    776795                return false;
    777 
    778         list($username, $expiration, $hmac) = $cookie_elements;
    779 
    780         return compact('username', 'expiration', 'hmac', 'scheme');
     796        }
     797
     798        list( $username, $expiration, $token, $hmac ) = $cookie_elements;
     799
     800        return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' );
    781801}
    782802endif;
     
    794814 * @param int $user_id User ID
    795815 * @param bool $remember Whether to remember the user
     816 * @param mixed $secure  Whether the admin cookies should only be sent over HTTPS.
     817 *                       Default is_ssl().
    796818 */
    797819function wp_set_auth_cookie($user_id, $remember = false, $secure = '') {
     
    855877        }
    856878
    857         $auth_cookie = wp_generate_auth_cookie($user_id, $expiration, $scheme);
    858         $logged_in_cookie = wp_generate_auth_cookie($user_id, $expiration, 'logged_in');
     879        $manager = WP_Session_Tokens::get_instance( $user_id );
     880        $token = $manager->create_token( $expiration );
     881
     882        $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
     883        $logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
    859884
    860885        /**
     
    16831708        }
    16841709
     1710        $token = wp_get_session_token();
    16851711        $i = wp_nonce_tick();
    16861712
    16871713        // Nonce generated 0-12 hours ago
    1688         if ( substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10) === $nonce )
     1714        if ( $nonce === substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 ) ) {
    16891715                return 1;
     1716        }
     1717
    16901718        // Nonce generated 12-24 hours ago
    1691         if ( substr(wp_hash(($i - 1) . $action . $uid, 'nonce'), -12, 10) === $nonce )
     1719        if ( $nonce === substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 ) ) {
    16921720                return 2;
     1721        }
     1722
    16931723        // Invalid nonce
    16941724        return false;
     
    17131743        }
    17141744
     1745        $token = wp_get_session_token();
    17151746        $i = wp_nonce_tick();
    17161747
    1717         return substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10);
     1748        return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
    17181749}
    17191750endif;
Note: See TracChangeset for help on using the changeset viewer.