From 923cfbc088cdf521efa85ee5599ce04ad58fdc92 Mon Sep 17 00:00:00 2001 From: Timotei Date: Tue, 9 Apr 2024 12:52:28 +0300 Subject: [PATCH 1/2] ESI - fix wp_create_nonce usage in php --- litespeed-cache.php | 68 +++++++++++++++++++++++++++++++++++++++++++++ src/core.cls.php | 2 ++ src/esi.cls.php | 60 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) diff --git a/litespeed-cache.php b/litespeed-cache.php index 65799190a..3f15c5a32 100644 --- a/litespeed-cache.php +++ b/litespeed-cache.php @@ -121,6 +121,74 @@ function litespeed_exception_handler($errno, $errstr, $errfile, $errline) } } +/** + * Override the WP verify nonce function + * @since 6.3 + */ +if (!function_exists('litespeed_define_verify_nonce_func')) { + function litespeed_define_verify_nonce_func() + { + /** + * If the nonce is in none_actions filter, convert it to ESI + */ + function wp_verify_nonce( $nonce, $action = -1 ) { + if (strlen($nonce) > 10) { + $nonce = \LiteSpeed\ESI::cls()->esi_hash_to_wp_nonce($nonce); + } + /* Reminder of this function is copied from wp-includes/pluggable.php (WP v6.4) */ + + $nonce = (string) $nonce; + $user = wp_get_current_user(); + $uid = (int) $user->ID; + if ( !$uid ) { + /** + * Filters whether the user who generated the nonce is logged out. + * + * @since 3.5.0 + * + * @param int $uid ID of the nonce-owning user. + * @param string|int $action The nonce action, or -1 if none was provided. + */ + $uid = apply_filters( 'nonce_user_logged_out', $uid, $action ); + } + + if ( empty( $nonce ) ) { + return false; + } + + $token = wp_get_session_token(); + $i = wp_nonce_tick( $action ); + + // Nonce generated 0-12 hours ago. + $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 ); + if ( hash_equals( $expected, $nonce ) ) { + return 1; + } + + // Nonce generated 12-24 hours ago. + $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 ); + if ( hash_equals( $expected, $nonce ) ) { + return 2; + } + + /** + * Fires when nonce verification fails. + * + * @since 4.4.0 + * + * @param string $nonce The invalid nonce. + * @param string|int $action The nonce action. + * @param WP_User $user The current user object. + * @param string $token The user's session token. + */ + do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token ); + + // Invalid nonce. + return false; + } + } +} + /** * Overwride the WP nonce funcs outside of LiteSpeed namespace * @since 3.0 diff --git a/src/core.cls.php b/src/core.cls.php index bd40ff0ff..0564b9c87 100644 --- a/src/core.cls.php +++ b/src/core.cls.php @@ -153,6 +153,8 @@ public function __construct() if ($this->cls('Router')->esi_enabled() && !function_exists('wp_create_nonce')) { Debug2::debug('[ESI] Overwrite wp_create_nonce()'); litespeed_define_nonce_func(); + Debug2::debug('[ESI] Overwrite wp_verify_nonce()'); + litespeed_define_verify_nonce_func(); } } diff --git a/src/esi.cls.php b/src/esi.cls.php index 25e724acb..4d6ccc807 100644 --- a/src/esi.cls.php +++ b/src/esi.cls.php @@ -1052,4 +1052,64 @@ public function contain_preserve_esi($content) } return $hit_list; } + + /** + * Convert nonce that has "get_preserve_content($nonce); + $nonce = $preserved_found ?: $nonce; + + // if nonce has with attribute "as-var=1" -> Is to have as-var important? + preg_match('/_esi_preserve_list as $k => $v) { + if($k === $hash){ + $return = $v; + break; + } + } + + return $return; + } } From fb8361bc6d8118cdd3dbf3e92b9263b1979d9e53 Mon Sep 17 00:00:00 2001 From: Timotei Date: Mon, 22 Apr 2024 21:13:01 +0300 Subject: [PATCH 2/2] Code review --- litespeed-cache.php | 1 + src/esi.cls.php | 49 +++++++++++++++++++++++++-------------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/litespeed-cache.php b/litespeed-cache.php index 3f15c5a32..173454cfc 100644 --- a/litespeed-cache.php +++ b/litespeed-cache.php @@ -132,6 +132,7 @@ function litespeed_define_verify_nonce_func() * If the nonce is in none_actions filter, convert it to ESI */ function wp_verify_nonce( $nonce, $action = -1 ) { + // If nonce length > 10 then render ESI to nonce value. if (strlen($nonce) > 10) { $nonce = \LiteSpeed\ESI::cls()->esi_hash_to_wp_nonce($nonce); } diff --git a/src/esi.cls.php b/src/esi.cls.php index 4d6ccc807..c6c1fa4bc 100644 --- a/src/esi.cls.php +++ b/src/esi.cls.php @@ -1061,30 +1061,35 @@ public function contain_preserve_esi($content) */ public function esi_hash_to_wp_nonce($nonce){ // Search the nonce in preserved list. If found return the content. - $preserved_found = $this->get_preserve_content($nonce); + $preserved_found = $this->get_preserve_content( $nonce ); $nonce = $preserved_found ?: $nonce; - // if nonce has with attribute "as-var=1" -> Is to have as-var important? - preg_match('/_esi_preserve_list as $k => $v) { - if($k === $hash){ - $return = $v; + foreach ( $this->_esi_preserve_list as $k => $v ) { + if( $k === $hash ){ + $return = $v; break; } }