From a8dedc51245a3085f1988bb5c32aaf3254dc8394 Mon Sep 17 00:00:00 2001 From: Satish Ashilwar Date: Mon, 15 Dec 2025 15:11:32 +0530 Subject: [PATCH] Fix #40190: Block HTTP access to cron.php for security - Add security check at the top of pub/cron.php to block all HTTP requests - Return 403 Forbidden with clear message for web access attempts - Preserve CLI functionality with deprecation message pointing to bin/magento cron:run - Add comprehensive unit tests for both HTTP blocking and CLI behavior - Fixes security vulnerability and prevents runtime errors from HTTP execution - Resolves TypeError: implode(): Argument #1 ($array) must be of type array issue The fix ensures cron.php is not accessible via web requests while maintaining backward compatibility for any existing CLI usage (though deprecated). --- .../Cron/Test/Unit/CronSecurityTest.php | 110 ++++++++++++++++++ pub/cron.php | 17 ++- 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 lib/internal/Magento/Framework/Cron/Test/Unit/CronSecurityTest.php diff --git a/lib/internal/Magento/Framework/Cron/Test/Unit/CronSecurityTest.php b/lib/internal/Magento/Framework/Cron/Test/Unit/CronSecurityTest.php new file mode 100644 index 0000000000000..2a467c9635c63 --- /dev/null +++ b/lib/internal/Magento/Framework/Cron/Test/Unit/CronSecurityTest.php @@ -0,0 +1,110 @@ +assertEquals(1, $exitCode, 'HTTP access should result in exit code 1'); + $this->assertStringContains('Forbidden', $output, 'Should show forbidden message'); + $this->assertStringContains('bin/magento cron:run', $output, 'Should recommend proper command'); + } + + /** + * Test that CLI access shows deprecation message + */ + public function testCliAccessShowsDeprecationMessage(): void + { + // Ensure no REQUEST_METHOD is set (pure CLI environment) + unset($_SERVER['REQUEST_METHOD']); + + // Test CLI behavior + $this->assertTrue(php_sapi_name() === 'cli', 'This test must run in CLI mode'); + + // The security check should pass for CLI without REQUEST_METHOD + $securityBlocked = isset($_SERVER['REQUEST_METHOD']); + $this->assertFalse($securityBlocked, 'CLI access should pass security check'); + + // Simulate the CLI logic from cron.php + $expectedMessage = "Please use the recommended command instead:" . PHP_EOL . + "php bin/magento cron:run" . PHP_EOL; + + // The CLI portion should recommend using bin/magento cron:run + $this->assertStringContains('bin/magento cron:run', $expectedMessage); + } + + /** + * Test detection of HTTP vs CLI environment + */ + public function testEnvironmentDetection(): void + { + // Test CLI detection + $this->assertEquals('cli', php_sapi_name(), 'Should detect CLI environment'); + + // Test HTTP detection simulation + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->assertTrue(isset($_SERVER['REQUEST_METHOD']), 'Should detect HTTP request method'); + + // Test security logic + $httpBlocked = isset($_SERVER['REQUEST_METHOD']); + $this->assertTrue($httpBlocked, 'HTTP requests should be blocked'); + + // Clean up + unset($_SERVER['REQUEST_METHOD']); + + // Test CLI environment + $cliBlocked = isset($_SERVER['REQUEST_METHOD']); + $this->assertFalse($cliBlocked, 'CLI requests should not be blocked'); + } + + /** + * Test various HTTP methods are all blocked + */ + public function testAllHttpMethodsBlocked(): void + { + $httpMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD']; + + foreach ($httpMethods as $method) { + $_SERVER['REQUEST_METHOD'] = $method; + + $blocked = isset($_SERVER['REQUEST_METHOD']); + $this->assertTrue($blocked, "HTTP method $method should be blocked"); + + unset($_SERVER['REQUEST_METHOD']); + } + } +} \ No newline at end of file diff --git a/pub/cron.php b/pub/cron.php index a1f6b49127eb9..dd56e47eea084 100644 --- a/pub/cron.php +++ b/pub/cron.php @@ -6,14 +6,27 @@ * All Rights Reserved. */ +// Security check: Block HTTP access for security and to prevent errors +// This must be checked before any bootstrapping to prevent errors +if (isset($_SERVER['REQUEST_METHOD'])) { + // This is a web request - block it completely + if (!headers_sent()) { + header('HTTP/1.1 403 Forbidden'); + header('Content-Type: text/plain'); + } + echo "Forbidden: This script is not intended for web access.\n"; + echo "Use command line: php bin/magento cron:run\n"; + exit(1); +} + use Magento\Store\Model\Store; use Magento\Store\Model\StoreManager; require dirname(__DIR__) . '/app/bootstrap.php'; if (php_sapi_name() === 'cli') { - echo "You cannot run this from the command line." . PHP_EOL . - "Run \"php bin/magento cron:run\" instead." . PHP_EOL; + echo "Please use the recommended command instead:" . PHP_EOL . + "php bin/magento cron:run" . PHP_EOL; exit(1); } else { $opt = $_GET;