From 50c50bea2e21e1e5440828b8ba7086fe18348cc3 Mon Sep 17 00:00:00 2001 From: kaldari Date: Tue, 3 Mar 2015 14:19:35 -0800 Subject: [PATCH] If no secret key is available, don't try to use cache In the unlikely event that no secret key is available, we shouldn't rely on the cache at all in TemplateParser. Adding new compileForEval() function and and moving eval() outside of if statement to prevent code duplication. Also, if the template fails integrity check, generate a notice instead of throwing an exception in case we change the secret key. Change-Id: Id44fdcc9533fc8a9c77e84fcebaa064f602477c6 --- includes/TemplateParser.php | 91 ++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 37 deletions(-) diff --git a/includes/TemplateParser.php b/includes/TemplateParser.php index a178fed4c3..0dbf2c73ea 100644 --- a/includes/TemplateParser.php +++ b/includes/TemplateParser.php @@ -97,57 +97,74 @@ class TemplateParser { // Fetch a secret key for building a keyed hash of the PHP code $config = ConfigFactory::getDefaultInstance()->makeConfig( 'main' ); - $secretKey = $config->get( 'SecretKey' ) ? : 'key'; - - // See if the compiled PHP code is stored in cache. - // CACHE_ACCEL throws an exception if no suitable object cache is present, so fall - // back to CACHE_ANYTHING. - try { - $cache = wfGetCache( CACHE_ACCEL ); - } catch ( Exception $e ) { - $cache = wfGetCache( CACHE_ANYTHING ); - } - $key = wfMemcKey( 'template', $templateName, $fastHash ); - $code = $this->forceRecompile ? null : $cache->get( $key ); - - if ( !$code ) { - // Compile the template into PHP code - $code = self::compile( $fileContents ); - - if ( !$code ) { - throw new Exception( "Could not compile template: {$filename}" ); + $secretKey = $config->get( 'SecretKey' ); + + if ( $secretKey ) { + // See if the compiled PHP code is stored in cache. + // CACHE_ACCEL throws an exception if no suitable object cache is present, so fall + // back to CACHE_ANYTHING. + try { + $cache = wfGetCache( CACHE_ACCEL ); + } catch ( Exception $e ) { + $cache = wfGetCache( CACHE_ANYTHING ); } + $key = wfMemcKey( 'template', $templateName, $fastHash ); + $code = $this->forceRecompile ? null : $cache->get( $key ); - // Strip the "compileForEval( $fileContents, $filename ); - // Prefix the code with a keyed hash (64 hex chars) as an integrity check - $code = hash_hmac( 'sha256', $code, $secretKey ) . $code; + // Prefix the code with a keyed hash (64 hex chars) as an integrity check + $code = hash_hmac( 'sha256', $code, $secretKey ) . $code; - // Cache the compiled PHP code - $cache->set( $key, $code ); - } else { - // Verify the integrity of the cached PHP code - $keyedHash = substr( $code, 0, 64 ); - $code = substr( $code, 64 ); - if ( $keyedHash === hash_hmac( 'sha256', $code, $secretKey ) ) { - $renderer = eval( $code ); + // Cache the compiled PHP code + $cache->set( $key, $code ); } else { - throw new Exception( "Template failed integrity check: {$filename}" ); + // Verify the integrity of the cached PHP code + $keyedHash = substr( $code, 0, 64 ); + $code = substr( $code, 64 ); + if ( $keyedHash !== hash_hmac( 'sha256', $code, $secretKey ) ) { + // Generate a notice if integrity check fails + trigger_error( "Template failed integrity check: {$filename}" ); + } } + // If there is no secret key available, don't use cache + } else { + $code = $this->compileForEval( $fileContents, $filename ); } + $renderer = eval( $code ); return $this->renderers[$templateName] = $renderer; } + /** + * Wrapper for compile() function that verifies successful compilation and strips + * out the '