summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrey Andreev <narf@devilix.net>2015-10-26 14:31:38 +0100
committerAndrey Andreev <narf@devilix.net>2015-10-31 17:55:30 +0100
commit0a6b0661305f20ac1fbd219d43f59193bea90d1d (patch)
treeea43dad00c9a93b64ea9c823c0702ddf937fc2d8
parent71b1b3f5b2dcc0f4b652e9494e9853b82541ac8c (diff)
Prevent Host header injections
-rw-r--r--application/config/config.php14
-rw-r--r--system/core/Config.php6
-rw-r--r--tests/codeigniter/core/Config_test.php47
3 files changed, 29 insertions, 38 deletions
diff --git a/application/config/config.php b/application/config/config.php
index 479d591a4..4f8f81406 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -11,10 +11,16 @@ defined('BASEPATH') OR exit('No direct script access allowed');
|
| http://example.com/
|
-| If this is not set then CodeIgniter will try guess the protocol, domain
-| and path to your installation. However, you should always configure this
-| explicitly and never rely on auto-guessing, especially in production
-| environments.
+| WARNING: You MUST set this value!
+|
+| If it is not set, then CodeIgniter will try guess the protocol and path
+| your installation, but due to security concerns the hostname will be set
+| to $_SERVER['SERVER_ADDR'] if available, or localhost otherwise.
+| The auto-detection mechanism exists only for convenience during
+| development and MUST NOT be used in production!
+|
+| If you need to allow multiple domains, remember that this file is still
+| a PHP script and you can easily do that on your own.
|
*/
$config['base_url'] = '';
diff --git a/system/core/Config.php b/system/core/Config.php
index feea7c85a..0264776f9 100644
--- a/system/core/Config.php
+++ b/system/core/Config.php
@@ -88,11 +88,9 @@ class CI_Config {
// Set the base_url automatically if none was provided
if (empty($this->config['base_url']))
{
- // The regular expression is only a basic validation for a valid "Host" header.
- // It's not exhaustive, only checks for valid characters.
- 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']))
+ if (isset($_SERVER['SERVER_ADDR']))
{
- $base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST']
+ $base_url = (is_https() ? 'https' : 'http').'://'.$_SERVER['SERVER_ADDR']
.substr($_SERVER['SCRIPT_NAME'], 0, strpos($_SERVER['SCRIPT_NAME'], basename($_SERVER['SCRIPT_FILENAME'])));
}
else
diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php
index f125fc6e9..26a5f32f5 100644
--- a/tests/codeigniter/core/Config_test.php
+++ b/tests/codeigniter/core/Config_test.php
@@ -79,46 +79,33 @@ class Config_test extends CI_TestCase {
$old_script_name = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : NULL;
$old_script_filename = $_SERVER['SCRIPT_FILENAME'];
$old_https = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : NULL;
+ $old_server_addr = isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : NULL;
- // Setup server vars for detection
- $host = 'test.com';
- $path = '/';
- $script = 'base_test.php';
- $_SERVER['HTTP_HOST'] = $host;
- $_SERVER['SCRIPT_NAME'] = $path.$script;
- $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/'.$script;
-
- // Rerun constructor
+ // The 'Host' header is user input and must not be trusted
+ $_SERVER['HTTP_HOST'] = 'test.com';
$this->config = new $cls;
+ $this->assertEquals('http://localhost/', $this->config->base_url());
- // Test plain detected (root)
- $this->assertEquals('http://'.$host.$path, $this->config->base_url());
-
- // Rerun constructor
- $path = '/path/';
- $_SERVER['SCRIPT_NAME'] = $path.$script;
- $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/'.$path.$script;
+ // However, we may fallback to the server's IP address
+ $_SERVER['SERVER_ADDR'] = '127.0.0.1';
+ $_SERVER['SCRIPT_NAME'] = '/base_test.php';
+ $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/base_test.php';
$this->config = new $cls;
+ $this->assertEquals('http://127.0.0.1/', $this->config->base_url());
- // Test plain detected (subfolder)
- $this->assertEquals('http://'.$host.$path, $this->config->base_url());
-
- // Rerun constructor
+ // Making sure that HTTPS and URI path are also detected
$_SERVER['HTTPS'] = 'on';
+ $_SERVER['SCRIPT_NAME'] = '/path/base_test.php';
+ $_SERVER['SCRIPT_FILENAME'] = '/foo/bar/path/base_test.php';
$this->config = new $cls;
-
- // Test secure detected
- $this->assertEquals('https://'.$host.$path, $this->config->base_url());
+ $this->assertEquals('https://127.0.0.1/path/', $this->config->base_url());
// Restore server vars
- if ($old_host === NULL) unset($_SERVER['HTTP_HOST']);
- else $_SERVER['HTTP_HOST'] = $old_host;
- if ($old_script_name === NULL) unset($_SERVER['SCRIPT_NAME']);
- else $_SERVER['SCRIPT_NAME'] = $old_script_name;
- if ($old_https === NULL) unset($_SERVER['HTTPS']);
- else $_SERVER['HTTPS'] = $old_https;
-
+ $_SERVER['HTTP_HOST'] = $old_host;
+ $_SERVER['SCRIPT_NAME'] = $old_script_name;
$_SERVER['SCRIPT_FILENAME'] = $old_script_filename;
+ $_SERVER['HTTPS'] = $old_https;
+ $_SERVER['SERVER_ADDR'] = $old_server_addr;
}
// --------------------------------------------------------------------