Skip to content

Commit 0a6b066

Browse files
committed
Prevent Host header injections
1 parent 71b1b3f commit 0a6b066

File tree

3 files changed

+29
-38
lines changed

3 files changed

+29
-38
lines changed

application/config/config.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,16 @@
1111
|
1212
| http://example.com/
1313
|
14-
| If this is not set then CodeIgniter will try guess the protocol, domain
15-
| and path to your installation. However, you should always configure this
16-
| explicitly and never rely on auto-guessing, especially in production
17-
| environments.
14+
| WARNING: You MUST set this value!
15+
|
16+
| If it is not set, then CodeIgniter will try guess the protocol and path
17+
| your installation, but due to security concerns the hostname will be set
18+
| to $_SERVER['SERVER_ADDR'] if available, or localhost otherwise.
19+
| The auto-detection mechanism exists only for convenience during
20+
| development and MUST NOT be used in production!
21+
|
22+
| If you need to allow multiple domains, remember that this file is still
23+
| a PHP script and you can easily do that on your own.
1824
|
1925
*/
2026
$config['base_url'] = '';

system/core/Config.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,9 @@ public function __construct()
8888
// Set the base_url automatically if none was provided
8989
if (empty($this->config['base_url']))
9090
{
91-
// The regular expression is only a basic validation for a valid "Host" header.
92-
// It's not exhaustive, only checks for valid characters.
93-
if (isset($_SERVER['HTTP_HOST']) && preg_match('/^((\[[0-9a-f:]+\])|(\d{1,3}(\.\d{1,3}){3})|[a-z0-9\-\.]+)(:\d+)?$/i', $_SERVER['HTTP_HOST']))
91+
if (isset($_SERVER['SERVER_ADDR']))
9492
{
95-
$base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST']
93+
$base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['SERVER_ADDR']
9694
.substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
9795
}
9896
else

tests/codeigniter/core/Config_test.php

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,46 +79,33 @@ public function test_base_url()
7979
$old_script_name = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL;
8080
$old_script_filename = $_SERVER['SCRIPT_FILENAME'];
8181
$old_https = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : NULL;
82+
$old_server_addr = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : NULL;
8283

83-
// Setup server vars for detection
84-
$host = 'test.com';
85-
$path = '/';
86-
$script = 'base_test.php';
87-
$_SERVER['HTTP_HOST'] = $host;
88-
$_SERVER['SCRIPT_NAME'] = $path.$script;
89-
$_SERVER['SCRIPT_FILENAME'] = '/foo/bar/'.$script;
90-
91-
// Rerun constructor
84+
// The 'Host' header is user input and must not be trusted
85+
$_SERVER['HTTP_HOST'] = 'test.com';
9286
$this->config = new $cls;
87+
$this->assertEquals('http://localhost/', $this->config->base_url());
9388

94-
// Test plain detected (root)
95-
$this->assertEquals('http://'.$host.$path, $this->config->base_url());
96-
97-
// Rerun constructor
98-
$path = '/path/';
99-
$_SERVER['SCRIPT_NAME'] = $path.$script;
100-
$_SERVER['SCRIPT_FILENAME'] = '/foo/bar/'.$path.$script;
89+
// However, we may fallback to the server's IP address
90+
$_SERVER['SERVER_ADDR'] = '127.0.0.1';
91+
$_SERVER['SCRIPT_NAME'] = '/base_test.php';
92+
$_SERVER['SCRIPT_FILENAME'] = '/foo/bar/base_test.php';
10193
$this->config = new $cls;
94+
$this->assertEquals('http://127.0.0.1/', $this->config->base_url());
10295

103-
// Test plain detected (subfolder)
104-
$this->assertEquals('http://'.$host.$path, $this->config->base_url());
105-
106-
// Rerun constructor
96+
// Making sure that HTTPS and URI path are also detected
10797
$_SERVER['HTTPS'] = 'on';
98+
$_SERVER['SCRIPT_NAME'] = '/path/base_test.php';
99+
$_SERVER['SCRIPT_FILENAME'] = '/foo/bar/path/base_test.php';
108100
$this->config = new $cls;
109-
110-
// Test secure detected
111-
$this->assertEquals('https://'.$host.$path, $this->config->base_url());
101+
$this->assertEquals('https://127.0.0.1/path/', $this->config->base_url());
112102

113103
// Restore server vars
114-
if ($old_host === NULL) unset($_SERVER['HTTP_HOST']);
115-
else $_SERVER['HTTP_HOST'] = $old_host;
116-
if ($old_script_name === NULL) unset($_SERVER['SCRIPT_NAME']);
117-
else $_SERVER['SCRIPT_NAME'] = $old_script_name;
118-
if ($old_https === NULL) unset($_SERVER['HTTPS']);
119-
else $_SERVER['HTTPS'] = $old_https;
120-
104+
$_SERVER['HTTP_HOST'] = $old_host;
105+
$_SERVER['SCRIPT_NAME'] = $old_script_name;
121106
$_SERVER['SCRIPT_FILENAME'] = $old_script_filename;
107+
$_SERVER['HTTPS'] = $old_https;
108+
$_SERVER['SERVER_ADDR'] = $old_server_addr;
122109
}
123110

124111
// --------------------------------------------------------------------

0 commit comments

Comments
 (0)