diff options
author | Henry Sudhof <kellanved@phpbb.com> | 2008-05-28 13:05:45 +0000 |
---|---|---|
committer | Henry Sudhof <kellanved@phpbb.com> | 2008-05-28 13:05:45 +0000 |
commit | 91b4fe1868ca2c4d81111943f781e3cfd0262ef2 (patch) | |
tree | 3c41b59d9938c5fa5e06b7b1c2d2b95b33437e3f /phpBB/includes | |
parent | 28e8c3ea8587f7dc2d37068a92ebd9d0dfc230c6 (diff) | |
download | forums-91b4fe1868ca2c4d81111943f781e3cfd0262ef2.tar forums-91b4fe1868ca2c4d81111943f781e3cfd0262ef2.tar.gz forums-91b4fe1868ca2c4d81111943f781e3cfd0262ef2.tar.bz2 forums-91b4fe1868ca2c4d81111943f781e3cfd0262ef2.tar.xz forums-91b4fe1868ca2c4d81111943f781e3cfd0262ef2.zip |
Merging mime and referer checks into the Trunk
git-svn-id: file:///svn/phpbb/trunk@8571 89ea8834-ac86-4346-8a33-228a782c2dd0
Diffstat (limited to 'phpBB/includes')
-rw-r--r-- | phpBB/includes/acp/acp_attachments.php | 4 | ||||
-rw-r--r-- | phpBB/includes/acp/acp_board.php | 11 | ||||
-rw-r--r-- | phpBB/includes/constants.php | 5 | ||||
-rw-r--r-- | phpBB/includes/functions_posting.php | 5 | ||||
-rw-r--r-- | phpBB/includes/functions_upload.php | 59 | ||||
-rw-r--r-- | phpBB/includes/functions_user.php | 2 | ||||
-rw-r--r-- | phpBB/includes/session.php | 56 |
7 files changed, 137 insertions, 5 deletions
diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index 2140aacff1..89769552bd 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -113,7 +113,9 @@ class acp_attachments 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false), 'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true), - 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'check_attachment_content' => array('lang' => 'CHECK_CONTENT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'legend2' => $l_legend_cat_images, 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 0e9be94550..800abd875a 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -319,6 +319,7 @@ class acp_board 'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), 'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'referer_validation' => array('lang' => 'REFERER_VALID', 'validate' => 'int:0:3','type' => 'custom', 'method' => 'select_ref_check', 'explain' => true), 'check_dnsbl' => array('lang' => 'CHECK_DNSBL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'email_check_mx' => array('lang' => 'EMAIL_CHECK_MX', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true), @@ -672,7 +673,17 @@ class acp_board return h_radio('config[ip_check]', $radio_ary, $value, $key); } + + /** + * Select referer validation + */ + function select_ref_check($value, $key = '') + { + $radio_ary = array(REFERER_VALIDATE_PATH => 'REF_PATH', REFERER_VALIDATE_HOST => 'REF_HOST', REFERER_VALIDATE_NONE => 'NO_REF_VALIDATION'); + return h_radio('config[referer_validation]', $radio_ary, $value, $key); + } + /** * Select account activation method */ diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index eb4eb77f22..7c681a4040 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -171,6 +171,11 @@ define('FIELD_BOOL', 4); define('FIELD_DROPDOWN', 5); define('FIELD_DATE', 6); +// referer validation +define('REFERER_VALIDATE_NONE', 0); +define('REFERER_VALIDATE_HOST', 1); +define('REFERER_VALIDATE_PATH', 2); + // Additional constants define('VOTE_CONVERTED', 127); diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 7d9945684d..877ba8c912 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -358,6 +358,11 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); $upload = new fileupload(); + if ($config['check_attachment_content']) + { + $upload->set_disallowed_content(explode('|', $config['mime_triggers'])); + } + if (!$local) { $filedata['post_attach'] = ($upload->is_valid($form_name)) ? true : false; diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 0a1ed1fab2..96c5562adf 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -228,6 +228,34 @@ class filespec { return @filesize($filename); } + + + /** + * Check the first 256 bytes for forbidden content + */ + function check_content($disallowed_content) + { + if (empty($disallowed_content)) + { + return true; + } + + $fp = @fopen($this->filename, 'rb'); + + if ($fp !== false) + { + $ie_mime_relevant = fread($fp, 256); + fclose($fp); + foreach ($disallowed_content as $forbidden) + { + if (stripos($ie_mime_relevant, '<' . $forbidden) !== false) + { + return false; + } + } + } + return true; + } /** * Move file to destination folder @@ -427,6 +455,7 @@ class fileerror extends filespec class fileupload { var $allowed_extensions = array(); + var $disallowed_content = array(); var $max_filesize = 0; var $min_width = 0; var $min_height = 0; @@ -446,12 +475,13 @@ class fileupload * @param int $max_height Maximum image height (only checked for images) * */ - function __construct($error_prefix = '', $allowed_extensions = false, $max_filesize = false, $min_width = false, $min_height = false, $max_width = false, $max_height = false) + function __construct($error_prefix = '', $allowed_extensions = false, $max_filesize = false, $min_width = false, $min_height = false, $max_width = false, $max_height = false, $disallowed_content = false) { $this->set_allowed_extensions($allowed_extensions); $this->set_max_filesize($max_filesize); $this->set_allowed_dimensions($min_width, $min_height, $max_width, $max_height); $this->set_error_prefix($error_prefix); + $this->set_disallowed_content($disallowed_content); } /** @@ -463,6 +493,7 @@ class fileupload $this->min_width = $this->min_height = $this->max_width = $this->max_height = 0; $this->error_prefix = ''; $this->allowed_extensions = array(); + $this->disallowed_content = array(); } /** @@ -497,6 +528,17 @@ class fileupload $this->max_filesize = (int) $max_filesize; } } + + /** + * Set disallowed strings + */ + function set_disallowed_content($disallowed_content) + { + if ($disallowed_content !== false && is_array($disallowed_content)) + { + $this->disallowed_content = $disallowed_content; + } + } /** * Set error prefix @@ -830,6 +872,12 @@ class fileupload { $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_EXTENSION'], $file->get('extension')); } + + // MIME Sniffing + if (!$this->valid_content($file)) + { + $file->error[] = sprintf($user->lang[$this->error_prefix . 'DISALLOWED_CONTENT']); + } } /** @@ -869,6 +917,15 @@ class fileupload return (isset($_FILES[$form_name]) && $_FILES[$form_name]['name'] != 'none') ? true : false; } + + /** + * Check for allowed extension + */ + function valid_content(&$file) + { + return ($file->check_content($this->disallowed_content)); + } + /** * Return image type/extension mapping */ diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index 40dc87b2e1..8519cd4fa6 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -1881,7 +1881,7 @@ function avatar_upload($data, &$error) // Init upload class include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx); - $upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height']); + $upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], explode('|', $config['mime_triggers'])); if (!empty($_FILES['uploadfile']['name'])) { diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index cb1f3bd8d0..6db65509ec 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -157,6 +157,7 @@ class session $this->cookie_data = array('u' => 0, 'k' => ''); $this->update_session_page = $update_session_page; $this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : ''; + $this->referer = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : ''; $this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? (string) $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; $this->host = (!empty($_SERVER['HTTP_HOST'])) ? (string) strtolower($_SERVER['HTTP_HOST']) : ((!empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : getenv('SERVER_NAME')); $this->page = $this->extract_current_page($phpbb_root_path); @@ -265,8 +266,18 @@ class session $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : ''; + + // referer checks + $check_referer_path = $config['referer_validation'] == REFERER_VALIDATE_PATH; + $referer_valid = true; + // we assume HEAD and TRACE to be foul play and thus only whitelist GET + if ($config['referer_validation'] && isset($_SERVER['REQUEST_METHOD']) && strtolower($_SERVER['REQUEST_METHOD']) !== 'get') + { + $referer_valid = $this->validate_referer($check_referer_path); + } + - if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for) + if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid) { $session_expired = false; @@ -344,7 +355,14 @@ class session // Added logging temporarly to help debug bugs... if (defined('DEBUG_EXTRA') && $this->data['user_id'] != ANONYMOUS) { - add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for)); + if ($referer_valid) + { + add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for)); + } + else + { + add_log('critical', 'LOG_REFERER_INVALID', $this->referer); + } } } } @@ -1271,6 +1289,40 @@ class session $this->set_login_key($user_id); } } + + + /** + * Check if the request originated from the same page. + * @param bool $check_script_path If true, the path will be checked as well + */ + function validate_referer($check_script_path = false) + { + // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason) + if (empty($this->referer) || empty($this->host) ) + { + return true; + } + $host = htmlspecialchars($this->host); + $ref = substr($this->referer, strpos($this->referer, '://') + 3); + if (!(stripos($ref , $host) === 0)) + { + return false; + } + else if ($check_script_path && rtrim($this->page['root_script_path'], '/') !== '') + { + $ref = substr($ref, strlen($host)); + $server_port = (!empty($_SERVER['SERVER_PORT'])) ? (int) $_SERVER['SERVER_PORT'] : (int) getenv('SERVER_PORT'); + if ($server_port !== 80 && $server_port !== 443 && stripos($ref, ":$server_port") === 0) + { + $ref = substr($ref, strlen(":$server_port")); + } + if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0)) + { + return false; + } + } + return true; + } } |