WordPress.org

Make WordPress Core

Ticket #20276: 20276.3.diff

File 20276.3.diff, 7.6 KB (added by duck_, 6 years ago)
  • src/wp-includes/pluggable.php

     
    494494 * @since 2.5.0
    495495 */
    496496function wp_logout() {
     497        wp_destroy_current_session();
    497498        wp_clear_auth_cookie();
    498499        do_action('wp_logout');
    499500}
     
    543544
    544545        $pass_frag = substr($user->user_pass, 8, 4);
    545546
    546         $key = wp_hash($username . $pass_frag . '|' . $expiration, $scheme);
    547         $hash = hash_hmac('md5', $username . '|' . $expiration, $key);
     547        $key = wp_hash($username . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme);
     548        $hash = hash_hmac('md5', $username . '|' . $expiration . '|' . $token, $key);
    548549
    549550        if ( $hmac != $hash ) {
    550551                do_action('auth_cookie_bad_hash', $cookie_elements);
     
    551552                return false;
    552553        }
    553554
     555        if ( ! wp_verify_session_token( $user->ID, $token ) ) {
     556                do_action( 'auth_cookie_bad_session_token', $cookie_elements );
     557                return false;
     558        }
     559
    554560        if ( $expiration < time() ) // AJAX/POST grace period set above
    555561                $GLOBALS['login_grace_period'] = 1;
    556562
     
    571577 * @param int $user_id User ID
    572578 * @param int $expiration Cookie expiration in seconds
    573579 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
     580 * @param string $token User's session token to use for this cookie
    574581 * @return string Authentication cookie contents
    575582 */
    576 function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
    577         $user = get_userdata($user_id);
     583function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth', $token = '') {
     584        $user = new WP_User($user_id);
     585        if ( ! $user->exists() )
     586                return '';
    578587
     588        if (empty($token))
     589                $token = wp_create_session_token( $user_id, $expiration );
     590
    579591        $pass_frag = substr($user->user_pass, 8, 4);
    580592
    581         $key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
    582         $hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
     593        $key = wp_hash($user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme);
     594        $hash = hash_hmac('md5', $user->user_login . '|' . $expiration . '|' . $token, $key);
    583595
    584         $cookie = $user->user_login . '|' . $expiration . '|' . $hash;
     596        $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
    585597
    586598        return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
    587599}
     
    625637        }
    626638
    627639        $cookie_elements = explode('|', $cookie);
    628         if ( count($cookie_elements) != 3 )
     640        if ( count($cookie_elements) != 4 )
    629641                return false;
    630642
    631         list($username, $expiration, $hmac) = $cookie_elements;
     643        list($username, $expiration, $token, $hmac) = $cookie_elements;
    632644
    633         return compact('username', 'expiration', 'hmac', 'scheme');
     645        return compact('username', 'expiration', 'token', 'hmac', 'scheme');
    634646}
    635647endif;
    636648
     
    646658 *
    647659 * @param int $user_id User ID
    648660 * @param bool $remember Whether to remember the user
     661 * @param mixed $secure Whether the admin cookies should only be sent over HTTPS (defaults to is_ssl())
    649662 */
    650663function wp_set_auth_cookie($user_id, $remember = false, $secure = '') {
    651664        if ( $remember ) {
     
    669682                $scheme = 'auth';
    670683        }
    671684
    672         $auth_cookie = wp_generate_auth_cookie($user_id, $expiration, $scheme);
    673         $logged_in_cookie = wp_generate_auth_cookie($user_id, $expiration, 'logged_in');
     685        $token = wp_create_session_token( $user_id, $expiration );
    674686
     687        $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
     688        $logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
     689
    675690        do_action('set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme);
    676691        do_action('set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in');
    677692
     
    12581273        $uid = (int) $user->ID;
    12591274        if ( ! $uid )
    12601275                $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    1261 
     1276        $token = wp_get_session_token();
    12621277        $i = wp_nonce_tick();
    12631278
    12641279        // Nonce generated 0-12 hours ago
    1265         if ( substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10) === $nonce )
     1280        if ( substr(wp_hash($i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10) === $nonce )
    12661281                return 1;
    12671282        // Nonce generated 12-24 hours ago
    1268         if ( substr(wp_hash(($i - 1) . $action . $uid, 'nonce'), -12, 10) === $nonce )
     1283        if ( substr(wp_hash(($i - 1) . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10) === $nonce )
    12691284                return 2;
    12701285        // Invalid nonce
    12711286        return false;
     
    12861301        $uid = (int) $user->ID;
    12871302        if ( ! $uid )
    12881303                $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    1289 
     1304        $token = wp_get_session_token();
    12901305        $i = wp_nonce_tick();
    12911306
    1292         return substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10);
     1307        return substr(wp_hash($i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10);
    12931308}
    12941309endif;
    12951310
  • src/wp-includes/user.php

     
    15501550        }
    15511551        return apply_filters( 'user_contactmethods', $user_contactmethods, $user );
    15521552}
     1553
     1554/**
     1555 * Generate a cookie session identification token.
     1556 *
     1557 * A session identification token is a long, random string. It is used to
     1558 * link a cookie to an expiration time and to ensure that cookies become
     1559 * invalidated upon logout. This function generates a token and stores it
     1560 * as user meta with the associated expiration time.
     1561 *
     1562 * Will also remove any expired tokens from the database.
     1563 *
     1564 * @since 3.7.0
     1565 *
     1566 * @param int $user_id User to create a token for.
     1567 * @param int $expiration Session expiration timestamp.
     1568 * @return string Session identification token.
     1569 */
     1570function wp_create_session_token( $user_id, $expiration ) {
     1571        $sessions = get_user_meta( $user_id, 'session_tokens', true );
     1572        if ( ! $sessions )
     1573                $sessions = array();
     1574        // Expire old sessions
     1575        $time = time();
     1576        foreach ( $sessions as $v => $e ) {
     1577                if ( $e < $time )
     1578                        unset( $sessions[ $v ] );
     1579        }
     1580
     1581        $token = wp_generate_password( 40, false, false );
     1582        $verifier = hash( 'sha256', $token );
     1583        $sessions[$verifier] = $expiration;
     1584
     1585        update_user_meta( $user_id, 'session_tokens', $sessions );
     1586
     1587        return $token;
     1588}
     1589
     1590/**
     1591 * Validate a user's session token as authentic.
     1592 *
     1593 * Checks that the given token is present in the database and hasn't expired.
     1594 *
     1595 * @since 3.7.0
     1596 *
     1597 * @param int $user_id User to verify against.
     1598 * @param string $token Token to verify.
     1599 * @return bool Whether the token is valid for the given user.
     1600 */
     1601function wp_verify_session_token( $user_id, $token ) {
     1602        $sessions = get_user_meta( $user_id, 'session_tokens', true );
     1603        $verifier = hash( 'sha256', $token );
     1604        return isset( $sessions[$verifier] ) && $sessions[$verifier] >= time();
     1605}
     1606
     1607/**
     1608 * Remove the current session token from the database.
     1609 *
     1610 * Will also remove any expired tokens from the database.
     1611 *
     1612 * @since 3.7.0
     1613 */
     1614function wp_destroy_current_session() {
     1615        $token = wp_get_session_token();
     1616        if ( ! empty( $token ) ) {
     1617                $user_id = get_current_user_id();
     1618                $verifier = hash( 'sha256', $token );
     1619                $sessions = get_user_meta( $user_id, 'session_tokens', true );
     1620                unset( $sessions[$verifier] );
     1621
     1622                // Expire old sessions
     1623                $time = time();
     1624                foreach ( $sessions as $v => $e ) {
     1625                        if ( $e < $time )
     1626                                unset( $sessions[ $v ] );
     1627                }
     1628
     1629                update_user_meta( $user_id, 'session_tokens', $sessions );
     1630        }
     1631}
     1632
     1633/**
     1634 * Retrieve the current session token from the logged_in cookie.
     1635 *
     1636 * @since 3.7.0
     1637 *
     1638 * @return string
     1639 */
     1640function wp_get_session_token() {
     1641        $cookie = wp_parse_auth_cookie( '', 'logged_in' );
     1642        return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
     1643}