So, tighten things up a little further. QA Team, please check this.

git-svn-id: file:///svn/phpbb/branches/phpBB-3_0_0@8554 89ea8834-ac86-4346-8a33-228a782c2dd0
This commit is contained in:
Henry Sudhof 2008-05-15 13:29:14 +00:00
parent ae3dd10604
commit 9413af5e1a
8 changed files with 77 additions and 8 deletions

View file

@ -103,6 +103,8 @@
<li>[Fix] Correctly sort by rank in memberlist (Bug #24435)</li> <li>[Fix] Correctly sort by rank in memberlist (Bug #24435)</li>
<li>[Fix] Purge cache after database restore (Bug #24245)</li> <li>[Fix] Purge cache after database restore (Bug #24245)</li>
<li>[Fix] Correctly display subforum read/unread icons from RTL in FF3, Konqueror and Safari3+. (thanks arod-1 for the fix, related to Bug #14830)</li> <li>[Fix] Correctly display subforum read/unread icons from RTL in FF3, Konqueror and Safari3+. (thanks arod-1 for the fix, related to Bug #14830)</li>
<li>[Feature] Added optional referer validation of POST requests as additional CSRF protection.</li>
<li>[Fix] Added missing form token in acp (thanks NBBN).</li>
</ul> </ul>
<a name="v300"></a><h3>1.ii. Changes since 3.0.0</h3> <a name="v300"></a><h3>1.ii. Changes since 3.0.0</h3>

View file

@ -323,6 +323,7 @@ class acp_board
'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true), '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), '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), '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), '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), '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), 'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),
@ -676,7 +677,17 @@ class acp_board
return h_radio('config[ip_check]', $radio_ary, $value, $key); 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 * Select account activation method
*/ */

View file

@ -171,6 +171,11 @@ define('FIELD_BOOL', 4);
define('FIELD_DROPDOWN', 5); define('FIELD_DROPDOWN', 5);
define('FIELD_DATE', 6); define('FIELD_DATE', 6);
// referer validation
define('REFERER_VALIDATE_NONE', 0);
define('REFERER_VALIDATE_HOST', 1);
define('REFERER_VALIDATE_PATH', 2);
// Additional constants // Additional constants
define('VOTE_CONVERTED', 127); define('VOTE_CONVERTED', 127);

View file

@ -158,6 +158,7 @@ class session
$this->cookie_data = array('u' => 0, 'k' => ''); $this->cookie_data = array('u' => 0, 'k' => '');
$this->update_session_page = $update_session_page; $this->update_session_page = $update_session_page;
$this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : ''; $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->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->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); $this->page = $this->extract_current_page($phpbb_root_path);
@ -263,8 +264,17 @@ class session
$s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : ''; $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) : ''; $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;
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; $session_expired = false;
@ -343,7 +353,14 @@ class session
// Added logging temporarly to help debug bugs... // Added logging temporarly to help debug bugs...
if (defined('DEBUG_EXTRA') && $this->data['user_id'] != ANONYMOUS) 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);
}
} }
} }
} }
@ -1279,6 +1296,35 @@ class session
$this->set_login_key($user_id); $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 && !empty(rtrim($this->page['root_script_path'], '/')))
{
$ref = substr($ref, strlen($host));
if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0))
{
return false;
}
}
return true;
}
} }

View file

@ -1740,6 +1740,10 @@ function change_database_data($version)
// TODO: remove all form token min times // TODO: remove all form token min times
break; break;
case '3.0.1':
set_config('referer_validation', '1');
} }
} }

View file

@ -184,6 +184,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('print_pm', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('queue_interval', '600'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('queue_interval', '600');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('ranks_path', 'images/ranks'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('ranks_path', 'images/ranks');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('require_activation', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('require_activation', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('referer_validation', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('script_path', ''); INSERT INTO phpbb_config (config_name, config_value) VALUES ('script_path', '');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('search_block_size', '250'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('search_block_size', '250');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('search_gc', '7200'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('search_gc', '7200');

View file

@ -206,10 +206,6 @@ $lang = array_merge($lang, array(
'ENABLE_COPPA_EXPLAIN' => 'This requires users to declare whether they are 13 or over for compliance with the U.S. COPPA. If this is disabled the COPPA specific groups will no longer be displayed.', 'ENABLE_COPPA_EXPLAIN' => 'This requires users to declare whether they are 13 or over for compliance with the U.S. COPPA. If this is disabled the COPPA specific groups will no longer be displayed.',
'MAX_CHARS' => 'Max', 'MAX_CHARS' => 'Max',
'MIN_CHARS' => 'Min', 'MIN_CHARS' => 'Min',
'MIN_TIME_REG' => 'Minimum time for registration',
'MIN_TIME_REG_EXPLAIN' => 'The registration form cannot be submitted before this time has passed.',
'MIN_TIME_TERMS' => 'Minimum time for accepting terms',
'MIN_TIME_TERMS_EXPLAIN' => 'The terms page cannot be skipped before this time has passed.',
'NO_AUTH_PLUGIN' => 'No suitable auth plugin found.', 'NO_AUTH_PLUGIN' => 'No suitable auth plugin found.',
'PASSWORD_LENGTH' => 'Password length', 'PASSWORD_LENGTH' => 'Password length',
'PASSWORD_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in passwords.', 'PASSWORD_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in passwords.',
@ -375,8 +371,6 @@ $lang = array_merge($lang, array(
'FORCE_PASS_CHANGE_EXPLAIN' => 'Require user to change their password after a set number of days. Setting this value to 0 disables this behaviour.', 'FORCE_PASS_CHANGE_EXPLAIN' => 'Require user to change their password after a set number of days. Setting this value to 0 disables this behaviour.',
'FORM_TIME_MAX' => 'Maximum time to submit forms', 'FORM_TIME_MAX' => 'Maximum time to submit forms',
'FORM_TIME_MAX_EXPLAIN' => 'The time a user has to submit a form. Use -1 to disable. Note that a form might become invalid if the session expires, regardless of this setting.', 'FORM_TIME_MAX_EXPLAIN' => 'The time a user has to submit a form. Use -1 to disable. Note that a form might become invalid if the session expires, regardless of this setting.',
'FORM_TIME_MIN' => 'Minimum time to submit forms',
'FORM_TIME_MIN_EXPLAIN' => 'Submissions faster than this time are ignored by the board. Use 0 to disable.',
'FORM_SID_GUESTS' => 'Tie forms to guest sessions', 'FORM_SID_GUESTS' => 'Tie forms to guest sessions',
'FORM_SID_GUESTS_EXPLAIN' => 'If enabled, the form token issued to guests will be session-exclusive. This can cause problems with some ISPs.', 'FORM_SID_GUESTS_EXPLAIN' => 'If enabled, the form token issued to guests will be session-exclusive. This can cause problems with some ISPs.',
'FORWARDED_FOR_VALID' => 'Validated <var>X_FORWARDED_FOR</var> header', 'FORWARDED_FOR_VALID' => 'Validated <var>X_FORWARDED_FOR</var> header',
@ -386,12 +380,17 @@ $lang = array_merge($lang, array(
'MAX_LOGIN_ATTEMPTS' => 'Maximum number of login attempts', 'MAX_LOGIN_ATTEMPTS' => 'Maximum number of login attempts',
'MAX_LOGIN_ATTEMPTS_EXPLAIN' => 'After this number of failed logins the user needs to additionally confirm his login visually (visual confirmation).', 'MAX_LOGIN_ATTEMPTS_EXPLAIN' => 'After this number of failed logins the user needs to additionally confirm his login visually (visual confirmation).',
'NO_IP_VALIDATION' => 'None', 'NO_IP_VALIDATION' => 'None',
'NO_REF_VALIDATION' => 'None',
'PASSWORD_TYPE' => 'Password complexity', 'PASSWORD_TYPE' => 'Password complexity',
'PASSWORD_TYPE_EXPLAIN' => 'Determines how complex a password needs to be when set or altered, subsequent options include the previous ones.', 'PASSWORD_TYPE_EXPLAIN' => 'Determines how complex a password needs to be when set or altered, subsequent options include the previous ones.',
'PASS_TYPE_ALPHA' => 'Must contain letters and numbers', 'PASS_TYPE_ALPHA' => 'Must contain letters and numbers',
'PASS_TYPE_ANY' => 'No requirements', 'PASS_TYPE_ANY' => 'No requirements',
'PASS_TYPE_CASE' => 'Must be mixed case', 'PASS_TYPE_CASE' => 'Must be mixed case',
'PASS_TYPE_SYMBOL' => 'Must contain symbols', 'PASS_TYPE_SYMBOL' => 'Must contain symbols',
'REF_HOST' => 'Only validate host',
'REF_PATH' => 'Also validate path',
'REFERER_VALID' => 'Validate Referer',
'REFERER_VALID_EXPLAIN' => 'If enabled, the referer of POST requests will be checked against the host/script path settings. This may cause issues with boards using several domains and or external logins.',
'TPL_ALLOW_PHP' => 'Allow php in templates', 'TPL_ALLOW_PHP' => 'Allow php in templates',
'TPL_ALLOW_PHP_EXPLAIN' => 'If this option is enabled, <code>PHP</code> and <code>INCLUDEPHP</code> statements will be recognised and parsed in templates.', 'TPL_ALLOW_PHP_EXPLAIN' => 'If this option is enabled, <code>PHP</code> and <code>INCLUDEPHP</code> statements will be recognised and parsed in templates.',
)); ));

View file

@ -608,6 +608,7 @@ $lang = array_merge($lang, array(
'LOG_REASON_REMOVED' => '<strong>Removed report/denial reason</strong><br />» %s', 'LOG_REASON_REMOVED' => '<strong>Removed report/denial reason</strong><br />» %s',
'LOG_REASON_UPDATED' => '<strong>Updated report/denial reason</strong><br />» %s', 'LOG_REASON_UPDATED' => '<strong>Updated report/denial reason</strong><br />» %s',
'LOG_REFERER_INVALID' => '<strong>Referer validation failed</strong><br />»Referer was “<em>%1$s</em>”. The request was rejected and the session killed.',
'LOG_RESET_DATE' => '<strong>Board start date reset</strong>', 'LOG_RESET_DATE' => '<strong>Board start date reset</strong>',
'LOG_RESET_ONLINE' => '<strong>Most users online reset</strong>', 'LOG_RESET_ONLINE' => '<strong>Most users online reset</strong>',
'LOG_RESYNC_POSTCOUNTS' => '<strong>User post counts resynchronised</strong>', 'LOG_RESYNC_POSTCOUNTS' => '<strong>User post counts resynchronised</strong>',