mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-03-25 18:32:17 -04:00
Security: Prevent Host Header Injection attacks by validating HTTP_HOST against a whitelist of allowed hostnames before constructing the baseURL. Changes: - Add getValidHost() method to validate HTTP_HOST against allowedHostnames - If allowedHostnames is empty, log warning and fall back to 'localhost' - If host not in whitelist, log warning and use first allowed hostname - Update .env.example with allowedHostnames documentation - Add security configuration section to INSTALL.md - Add unit tests for host validation This addresses the security advisory where the application constructed baseURL from the attacker-controllable HTTP_HOST header, allowing: - Login form phishing via manipulated form actions - Cache poisoning via poisoned asset URLs Fixes GHSA-jchf-7hr6-h4f3
126 lines
3.7 KiB
PHP
126 lines
3.7 KiB
PHP
<?php
|
|
|
|
namespace Tests\Config;
|
|
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use Config\App;
|
|
|
|
class AppTest extends CIUnitTestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testGetValidHostReturnsHostWhenValid(): void
|
|
{
|
|
$app = new class extends App {
|
|
public array $allowedHostnames = ['example.com', 'www.example.com'];
|
|
|
|
public function __construct() {}
|
|
};
|
|
|
|
$reflection = new \ReflectionClass($app);
|
|
$method = $reflection->getMethod('getValidHost');
|
|
$method->setAccessible(true);
|
|
|
|
$_SERVER['HTTP_HOST'] = 'example.com';
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('example.com', $host);
|
|
|
|
$_SERVER['HTTP_HOST'] = 'www.example.com';
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('www.example.com', $host);
|
|
}
|
|
|
|
public function testGetValidHostReturnsFallbackForInvalidHost(): void
|
|
{
|
|
$app = new class extends App {
|
|
public array $allowedHostnames = ['example.com', 'www.example.com'];
|
|
|
|
public function __construct() {}
|
|
};
|
|
|
|
$reflection = new \ReflectionClass($app);
|
|
$method = $reflection->getMethod('getValidHost');
|
|
$method->setAccessible(true);
|
|
|
|
$_SERVER['HTTP_HOST'] = 'malicious.com';
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('example.com', $host);
|
|
|
|
$_SERVER['HTTP_HOST'] = 'evil.org';
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('example.com', $host);
|
|
}
|
|
|
|
public function testGetValidHostReturnsLocalhostWhenNoWhitelist(): void
|
|
{
|
|
$app = new class extends App {
|
|
public array $allowedHostnames = [];
|
|
|
|
public function __construct() {}
|
|
};
|
|
|
|
$reflection = new \ReflectionClass($app);
|
|
$method = $reflection->getMethod('getValidHost');
|
|
$method->setAccessible(true);
|
|
|
|
$_SERVER['HTTP_HOST'] = 'malicious.com';
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('localhost', $host);
|
|
|
|
$_SERVER['HTTP_HOST'] = 'example.com';
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('localhost', $host);
|
|
}
|
|
|
|
public function testGetValidHostHandlesMissingHttpHost(): void
|
|
{
|
|
$app = new class extends App {
|
|
public array $allowedHostnames = ['example.com'];
|
|
|
|
public function __construct() {}
|
|
};
|
|
|
|
$reflection = new \ReflectionClass($app);
|
|
$method = $reflection->getMethod('getValidHost');
|
|
$method->setAccessible(true);
|
|
|
|
unset($_SERVER['HTTP_HOST']);
|
|
$host = $method->invoke($app);
|
|
$this->assertEquals('example.com', $host);
|
|
}
|
|
|
|
public function testBaseURLContainsValidHost(): void
|
|
{
|
|
$_SERVER['HTTP_HOST'] = 'example.com';
|
|
$_SERVER['SCRIPT_NAME'] = '/index.php';
|
|
$_SERVER['HTTPS'] = null;
|
|
|
|
$app = new class extends App {
|
|
public array $allowedHostnames = ['example.com'];
|
|
};
|
|
|
|
$this->assertStringContainsString('example.com', $app->baseURL);
|
|
}
|
|
|
|
public function testBaseURLUsesFallbackHostWhenInvalidHostProvided(): void
|
|
{
|
|
$_SERVER['HTTP_HOST'] = 'malicious.com';
|
|
$_SERVER['SCRIPT_NAME'] = '/index.php';
|
|
$_SERVER['HTTPS'] = null;
|
|
|
|
$app = new class extends App {
|
|
public array $allowedHostnames = ['example.com'];
|
|
};
|
|
|
|
$this->assertStringContainsString('example.com', $app->baseURL);
|
|
$this->assertStringNotContainsString('malicious.com', $app->baseURL);
|
|
}
|
|
} |