WordPress.org

Make WordPress Core

Ticket #20276: 20276.2.diff

File 20276.2.diff, 7.5 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                return false;
     557        }
     558
    554559        if ( $expiration < time() ) // AJAX/POST grace period set above
    555560                $GLOBALS['login_grace_period'] = 1;
    556561
     
    571576 * @param int $user_id User ID
    572577 * @param int $expiration Cookie expiration in seconds
    573578 * @param string $scheme Optional. The cookie scheme to use: auth, secure_auth, or logged_in
     579 * @param string $token User's session token to use for this cookie
    574580 * @return string Authentication cookie contents
    575581 */
    576 function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth') {
    577         $user = get_userdata($user_id);
     582function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth', $token = '') {
     583        $user = new WP_User($user_id);
     584        if ( ! $user->exists() )
     585                return '';
    578586
     587        if (empty($token))
     588                $token = wp_create_session_token( $user_id, $expiration );
     589
    579590        $pass_frag = substr($user->user_pass, 8, 4);
    580591
    581         $key = wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme);
    582         $hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key);
     592        $key = wp_hash($user->user_login . '|' . $pass_frag . '|' . $expiration . '|' . $token, $scheme);
     593        $hash = hash_hmac('md5', $user->user_login . '|' . $expiration . '|' . $token, $key);
    583594
    584         $cookie = $user->user_login . '|' . $expiration . '|' . $hash;
     595        $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash;
    585596
    586597        return apply_filters('auth_cookie', $cookie, $user_id, $expiration, $scheme);
    587598}
     
    625636        }
    626637
    627638        $cookie_elements = explode('|', $cookie);
    628         if ( count($cookie_elements) != 3 )
     639        if ( count($cookie_elements) != 4 )
    629640                return false;
    630641
    631         list($username, $expiration, $hmac) = $cookie_elements;
     642        list($username, $expiration, $token, $hmac) = $cookie_elements;
    632643
    633         return compact('username', 'expiration', 'hmac', 'scheme');
     644        return compact('username', 'expiration', 'token', 'hmac', 'scheme');
    634645}
    635646endif;
    636647
     
    646657 *
    647658 * @param int $user_id User ID
    648659 * @param bool $remember Whether to remember the user
     660 * @param mixed $secure Whether the admin cookies should only be sent over HTTPS (defaults to is_ssl())
    649661 */
    650662function wp_set_auth_cookie($user_id, $remember = false, $secure = '') {
    651663        if ( $remember ) {
     
    669681                $scheme = 'auth';
    670682        }
    671683
    672         $auth_cookie = wp_generate_auth_cookie($user_id, $expiration, $scheme);
    673         $logged_in_cookie = wp_generate_auth_cookie($user_id, $expiration, 'logged_in');
     684        $token = wp_create_session_token( $user_id, $expiration );
    674685
     686        $auth_cookie = wp_generate_auth_cookie( $user_id, $expiration, $scheme, $token );
     687        $logged_in_cookie = wp_generate_auth_cookie( $user_id, $expiration, 'logged_in', $token );
     688
    675689        do_action('set_auth_cookie', $auth_cookie, $expire, $expiration, $user_id, $scheme);
    676690        do_action('set_logged_in_cookie', $logged_in_cookie, $expire, $expiration, $user_id, 'logged_in');
    677691
     
    12581272        $uid = (int) $user->ID;
    12591273        if ( ! $uid )
    12601274                $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    1261 
     1275        $token = wp_get_session_token();
    12621276        $i = wp_nonce_tick();
    12631277
    12641278        // Nonce generated 0-12 hours ago
    1265         if ( substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10) === $nonce )
     1279        if ( substr(wp_hash($i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10) === $nonce )
    12661280                return 1;
    12671281        // Nonce generated 12-24 hours ago
    1268         if ( substr(wp_hash(($i - 1) . $action . $uid, 'nonce'), -12, 10) === $nonce )
     1282        if ( substr(wp_hash(($i - 1) . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10) === $nonce )
    12691283                return 2;
    12701284        // Invalid nonce
    12711285        return false;
     
    12861300        $uid = (int) $user->ID;
    12871301        if ( ! $uid )
    12881302                $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
    1289 
     1303        $token = wp_get_session_token();
    12901304        $i = wp_nonce_tick();
    12911305
    1292         return substr(wp_hash($i . $action . $uid, 'nonce'), -12, 10);
     1306        return substr(wp_hash($i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10);
    12931307}
    12941308endif;
    12951309
  • 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        $sessions = array_filter( $sessions, '_session_not_expired' );
     1575
     1576        $token = wp_generate_password( 40, false, false );
     1577        $verifier = hash( 'sha256', $token );
     1578        $sessions[$verifier] = $expiration;
     1579
     1580        update_user_meta( $user_id, 'session_tokens', $sessions );
     1581
     1582        return $token;
     1583}
     1584
     1585/**
     1586 * Validate a user's session token as authentic.
     1587 *
     1588 * Checks that the given token is present in the database and hasn't expired.
     1589 *
     1590 * @since 3.7.0
     1591 *
     1592 * @param int $user_id User to verify against.
     1593 * @param string $token Token to verify.
     1594 * @return bool Whether the token is valid for the given user.
     1595 */
     1596function wp_verify_session_token( $user_id, $token ) {
     1597        $sessions = get_user_meta( $user_id, 'session_tokens', true );
     1598        $verifier = hash( 'sha256', $token );
     1599        return isset( $sessions[$verifier] ) && $sessions[$verifier] >= time();
     1600}
     1601
     1602/**
     1603 * Remove the current session token from the database.
     1604 *
     1605 * Will also remove any expired tokens from the database.
     1606 *
     1607 * @since 3.7.0
     1608 */
     1609function wp_destroy_current_session() {
     1610        $token = wp_get_session_token();
     1611        if ( ! empty( $token ) ) {
     1612                $user_id = get_current_user_id();
     1613                $verifier = hash( 'sha256', $token );
     1614                $sessions = get_user_meta( $user_id, 'session_tokens', true );
     1615                unset( $sessions[$verifier] );
     1616                $sessions = array_filter( $sessions, '_session_not_expired' );
     1617                update_user_meta( $user_id, 'session_tokens', $sessions );
     1618        }
     1619}
     1620
     1621/**
     1622 * @access private
     1623 * @since 3.7.0
     1624 * @param int $expiry
     1625 */
     1626function _session_not_expired( $expiry ) {
     1627        return $expiry >= time();
     1628}
     1629
     1630/**
     1631 * Retrieve the current session token from the logged_in cookie.
     1632 *
     1633 * @since 3.7.0
     1634 *
     1635 * @return string
     1636 */
     1637function wp_get_session_token() {
     1638        $cookie = wp_parse_auth_cookie( '', 'logged_in' );
     1639        return ! empty( $cookie['token'] ) ? $cookie['token'] : '';
     1640}