Moved csrftoken stuff into a class
added getCurrentIP method to user class added config option for sitewide csrf protection
This commit is contained in:
parent
19a0945be2
commit
a56140ca84
@ -53,6 +53,7 @@ require_once(CLASS_DIR . '/bitcoinwrapper.class.php');
|
||||
require_once(CLASS_DIR . '/monitoring.class.php');
|
||||
require_once(CLASS_DIR . '/notification.class.php');
|
||||
require_once(CLASS_DIR . '/user.class.php');
|
||||
require_once(CLASS_DIR . '/csrftoken.class.php');
|
||||
require_once(CLASS_DIR . '/invitation.class.php');
|
||||
require_once(CLASS_DIR . '/share.class.php');
|
||||
require_once(CLASS_DIR . '/worker.class.php');
|
||||
|
||||
@ -73,6 +73,9 @@ class Base {
|
||||
public function setTokenType($tokentype) {
|
||||
$this->tokentype = $tokentype;
|
||||
}
|
||||
public function setCSRFToken($token) {
|
||||
$this->CSRFToken = $token;
|
||||
}
|
||||
public function setShare($share) {
|
||||
$this->share = $share;
|
||||
}
|
||||
|
||||
45
public/include/classes/csrftoken.class.php
Normal file
45
public/include/classes/csrftoken.class.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
// Make sure we are called from index.php
|
||||
if (!defined('SECURITY')) die('Hacking attempt');
|
||||
|
||||
class CSRFToken Extends Base {
|
||||
/**
|
||||
* Gets a basic CSRF token for this user/type and time chunk
|
||||
* @param string User; for hash seed, if username isn't available use IP
|
||||
* @param string Type of token; for hash seed, should be unique per page/use
|
||||
* @return string CSRF token
|
||||
*/
|
||||
public function getBasic($user, $type) {
|
||||
$date = date('m/d/y/H/i/s');
|
||||
$data = explode('/', $date);
|
||||
$month = $data[0]; $day = $data[1]; $year = $data[2];
|
||||
$hour = $data[3]; $minute = $data[4]; $second = $data[5];
|
||||
$seed = $this->salty;
|
||||
$lead = $this->config['csrf']['options']['leadtime'];
|
||||
if ($lead >= 11) { $lead = 10; }
|
||||
if ($lead <= 0) { $lead = 3; }
|
||||
if ($minute == 59 && $second > (60-$lead)) {
|
||||
$minute = 0;
|
||||
$fhour = ($hour == 23) ? $hour = 0 : $hour+=1;
|
||||
}
|
||||
$seed = $seed.$month.$day.$user.$type.$year.$hour.$minute.$seed;
|
||||
return $this->getHash($seed);
|
||||
}
|
||||
|
||||
private function getHash($string) {
|
||||
return hash('sha256', $this->salty.$string.$this->salt);
|
||||
}
|
||||
}
|
||||
|
||||
$csrftoken = new CSRFToken();
|
||||
$csrftoken->setDebug($debug);
|
||||
$csrftoken->setMysql($mysqli);
|
||||
$csrftoken->setSalt(SALT);
|
||||
$csrftoken->setSalty(SALTY);
|
||||
$csrftoken->setMail($mail);
|
||||
$csrftoken->setUser($user);
|
||||
$csrftoken->setToken($oToken);
|
||||
$csrftoken->setConfig($config);
|
||||
$csrftoken->setErrorCodes($aErrorCodes);
|
||||
?>
|
||||
@ -794,26 +794,36 @@ class User extends Base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current CSRF token for this user/type setting and time chunk
|
||||
* @param string User; for hash seed, if username isn't available use IP
|
||||
* @param string Type of token; for hash seed, should be unique per page/use
|
||||
* @return string CSRF token
|
||||
* Convenience function to get IP address, no params is the same as REMOTE_ADDR
|
||||
* @param trustremote bool must be FALSE to checkclient or checkforwarded
|
||||
* @param checkclient bool check HTTP_CLIENT_IP for a valid ip first
|
||||
* @param checkforwarded bool check HTTP_X_FORWARDED_FOR for a valid ip first
|
||||
* @return string IP address
|
||||
*/
|
||||
public function getCSRFToken($user, $type) {
|
||||
$date = date('m/d/y/H/i/s');
|
||||
$data = explode('/', $date);
|
||||
$month = $data[0]; $day = $data[1]; $year = $data[2];
|
||||
$hour = $data[3]; $minute = $data[4]; $second = $data[5];
|
||||
$seed = $this->salty;
|
||||
$lead = $this->config['csrf']['options']['leadtime'];
|
||||
if ($lead >= 11) { $lead = 10; }
|
||||
if ($lead <= 0) { $lead = 3; }
|
||||
if ($minute == 59 && $second > (60-$lead)) {
|
||||
$minute = 0;
|
||||
$fhour = ($hour == 23) ? $hour = 0 : $hour+=1;
|
||||
public function getCurrentIP($trustremote=true, $checkclient=false, $checkforwarded=false) {
|
||||
$client = (isset($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : false;
|
||||
$fwd = (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : false;
|
||||
$remote = (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : @$_SERVER['REMOTE_ADDR'];
|
||||
// shared internet
|
||||
if (filter_var($client, FILTER_VALIDATE_IP) && !$trustremote && $checkclient) {
|
||||
return $client;
|
||||
} else if (strpos($fwd, ',') !== false && !$trustremote && $checkforwarded) {
|
||||
// multiple proxies
|
||||
$ips = explode(',', $fwd);
|
||||
$path = array();
|
||||
foreach ($ips as $ip) {
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
||||
$path[] = $ip;
|
||||
}
|
||||
}
|
||||
return array_pop($path);
|
||||
} else if (filter_var($fwd, FILTER_VALIDATE_IP) && !$trustremote && $checkforwarded) {
|
||||
// single
|
||||
return $fwd;
|
||||
} else {
|
||||
// as usual
|
||||
return $remote;
|
||||
}
|
||||
$seed = $seed.$month.$day.$user.$type.$year.$hour.$minute.$seed;
|
||||
return $this->getHash($seed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,7 +832,6 @@ $user = new User();
|
||||
$user->setDebug($debug);
|
||||
$user->setMysql($mysqli);
|
||||
$user->setSalt(SALT);
|
||||
$user->setSalty(SALTY);
|
||||
$user->setSmarty($smarty);
|
||||
$user->setConfig($config);
|
||||
$user->setMail($mail);
|
||||
|
||||
@ -135,15 +135,18 @@ $config['twofactor']['options']['changepw'] = true;
|
||||
*
|
||||
* Options:
|
||||
* enabled = Whether or not we will generate/check for valid CSRF tokens
|
||||
* leadtime = Length of time in seconds to give as leeway, 1-10s
|
||||
* login = Use and check CSRF tokens for the login forms
|
||||
* sitewide = Require a valid CSRF token for all forms, does not override specific form settings
|
||||
* leadtime = Length of time in seconds to give as leeway between minute switches
|
||||
* login = Use and check login-specific CSRF token
|
||||
*
|
||||
* Default:
|
||||
* enabled = true
|
||||
* sitewide = true
|
||||
* leadtime = 3
|
||||
* login = true
|
||||
*/
|
||||
$config['csrf']['enabled'] = true;
|
||||
$config['csrf']['sitewide'] = true;
|
||||
$config['csrf']['options']['leadtime'] = 3;
|
||||
$config['csrf']['forms']['login'] = true;
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) {
|
||||
// csrf token - update if it's enabled
|
||||
$token = '';
|
||||
if ($config['csrf']['enabled'] && $config['csrf']['forms']['login']) {
|
||||
$token = $user->getCSRFToken($_SERVER['REMOTE_ADDR'], 'login');
|
||||
$token = $csrftoken->getBasic($user->getCurrentIP(), 'login');
|
||||
}
|
||||
// Load news entries for Desktop site and unauthenticated users
|
||||
$smarty->assign("CONTENT", "default.tpl");
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
// Make sure we are called from index.php
|
||||
if (!defined('SECURITY')) die('Hacking attempt');
|
||||
|
||||
|
||||
// ReCaptcha handling if enabled
|
||||
if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins')) {
|
||||
require_once(INCLUDE_DIR . '/lib/recaptchalib.php');
|
||||
@ -37,7 +36,7 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserId($_POST
|
||||
}
|
||||
}
|
||||
if ($config['csrf']['enabled'] && $config['csrf']['forms']['login']) {
|
||||
if ((isset($_POST['ctoken']) && $_POST['ctoken'] !== $user->getCSRFToken($_SERVER['REMOTE_ADDR'], 'login')) || (!isset($_POST['ctoken']))) {
|
||||
if ((isset($_POST['ctoken']) && $_POST['ctoken'] !== $csrftoken->getBasic($user->getCurrentIP(), 'login')) || (!isset($_POST['ctoken']))) {
|
||||
// csrf protection is on and this token is invalid, error out -> time expired
|
||||
$nocsrf = 0;
|
||||
}
|
||||
@ -61,7 +60,7 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserId($_POST
|
||||
// csrf token - update if it's enabled
|
||||
$token = '';
|
||||
if ($config['csrf']['enabled'] && $config['csrf']['forms']['login']) {
|
||||
$token = $user->getCSRFToken($_SERVER['REMOTE_ADDR'], 'login');
|
||||
$token = $csrftoken->getBasic($user->getCurrentIP(), 'login');
|
||||
}
|
||||
|
||||
// Load login template
|
||||
|
||||
Loading…
Reference in New Issue
Block a user