From d57aed4049afdae6dd72d0dd7f42d13bda451a21 Mon Sep 17 00:00:00 2001 From: xisi Date: Fri, 24 Jan 2014 11:18:07 -0500 Subject: [PATCH 01/30] basic test stuff --- tests/bootstrap.php | 23 +++++++++++++++++++ tests/config.php | 11 +++++++++ tests/phpunit.xml | 13 +++++++---- tests/unit/config/SampleTest.php | 11 +++------ .../unit/securityregress/SecurityRegress.php | 13 +++++++++++ 5 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 tests/bootstrap.php create mode 100644 tests/config.php create mode 100644 tests/unit/securityregress/SecurityRegress.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 00000000..3aa4c274 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/tests/config.php b/tests/config.php new file mode 100644 index 00000000..a4beacb8 --- /dev/null +++ b/tests/config.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 6cafbdac..258e159e 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -1,5 +1,10 @@ + - - unit/config - - \ No newline at end of file + + unit/config + + + unit/securityregress/SecurityRegress.php + + + \ No newline at end of file diff --git a/tests/unit/config/SampleTest.php b/tests/unit/config/SampleTest.php index 9b445a57..3ee6c140 100644 --- a/tests/unit/config/SampleTest.php +++ b/tests/unit/config/SampleTest.php @@ -2,17 +2,12 @@ // these are ONLY here because we're checking config options // these should NOT be in a normal unit test -define('SECURITY', 'so we can check config options'); -define("BASEPATH", "./"); - -require_once(BASEPATH.'public/include/config/global.inc.dist.php'); -require_once("PHPUnit/Autoload.php"); class TestDistConfig extends PHPUnit_Framework_Testcase { /** -* Test to make sure SALT is sane -*/ - function testSalt() { + * Test to make sure SALT is sane + */ + function testSaltLength() { $this->assertNotEmpty(SALT); $this->assertGreaterThan(1, strlen(SALT)); } diff --git a/tests/unit/securityregress/SecurityRegress.php b/tests/unit/securityregress/SecurityRegress.php new file mode 100644 index 00000000..6e40ce1d --- /dev/null +++ b/tests/unit/securityregress/SecurityRegress.php @@ -0,0 +1,13 @@ + \ No newline at end of file From 7393f21d0185878e60fda908de53b167517e7d3e Mon Sep 17 00:00:00 2001 From: xisi Date: Fri, 24 Jan 2014 18:49:06 -0500 Subject: [PATCH 02/30] just pushing so I can rebase zzz --- public/index.php | 2 +- tests/config.dist.php | 10 ++++ tests/config.php | 1 - tests/phpunit.xml | 7 ++- .../unit/securityregress/SecurityRegress.php | 13 ------ .../securityregress/Security_CSRFToken.php | 46 +++++++++++++++++++ .../securityregress/Security_Sessions.php | 30 ++++++++++++ 7 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 tests/config.dist.php delete mode 100644 tests/unit/securityregress/SecurityRegress.php create mode 100644 tests/unit/securityregress/Security_CSRFToken.php create mode 100644 tests/unit/securityregress/Security_Sessions.php diff --git a/public/index.php b/public/index.php index 0c1fbd09..30279049 100644 --- a/public/index.php +++ b/public/index.php @@ -118,4 +118,4 @@ if (!@$supress_master) $smarty->display($master_template, $smarty_cache_key); // Unset any temporary values here unset($_SESSION['POPUP']); -?> \ No newline at end of file +?> diff --git a/tests/config.dist.php b/tests/config.dist.php new file mode 100644 index 00000000..21da7475 --- /dev/null +++ b/tests/config.dist.php @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/tests/config.php b/tests/config.php index a4beacb8..cbcdb1af 100644 --- a/tests/config.php +++ b/tests/config.php @@ -1,7 +1,6 @@ unit/config - - unit/securityregress/SecurityRegress.php + + unit/securityregress/Security_CSRFToken.php + + + unit/securityregress/Security_Sessions.php \ No newline at end of file diff --git a/tests/unit/securityregress/SecurityRegress.php b/tests/unit/securityregress/SecurityRegress.php deleted file mode 100644 index 6e40ce1d..00000000 --- a/tests/unit/securityregress/SecurityRegress.php +++ /dev/null @@ -1,13 +0,0 @@ - \ No newline at end of file diff --git a/tests/unit/securityregress/Security_CSRFToken.php b/tests/unit/securityregress/Security_CSRFToken.php new file mode 100644 index 00000000..beb01644 --- /dev/null +++ b/tests/unit/securityregress/Security_CSRFToken.php @@ -0,0 +1,46 @@ +getBasic($user->getCurrentIP(), 'test-token'); + $test_token = $csrftoken->checkBasic($user->getCurrentIP(), 'test-token', $created_token); + $this->assertTrue($test_token); + $this->assertAttributeEquals($csrftoken->valid, true); + } + + /** + * Tests if a CSRF token correctly fails + */ + function testCSRFToken_fail() { + global $config; + global $user; + global $csrftoken; + + // differing user + $created_token = $csrftoken->getBasic('not the same', 'test-token'); + $test_token = $csrftoken->checkBasic($user->getCurrentIP(), 'test-token', $created_token); + $this->assertFalse($test_token); + + // differing type + $created_token2 = $csrftoken->getBasic($user->getCurrentIP(), 'not the same'); + $test_token2 = $csrftoken->checkBasic($user->getCurrentIP(), 'test-token', $created_token2); + $this->assertFalse($test_token2); + + // token slightly shortened + $created_token3 = $csrftoken->getBasic($user->getCurrentIP(), 'test-token'); + $created_token3 = substr($created_token3, 0, (strlen($created_token3)-1)); + $test_token3 = $csrftoken->checkBasic($user->getCurrentIP(), 'test-token', $created_token3); + $this->assertFalse($test_token3); + } +} + +?> \ No newline at end of file diff --git a/tests/unit/securityregress/Security_Sessions.php b/tests/unit/securityregress/Security_Sessions.php new file mode 100644 index 00000000..5813f5a1 --- /dev/null +++ b/tests/unit/securityregress/Security_Sessions.php @@ -0,0 +1,30 @@ +assertNotEquals($mid, session_id()); + } + } +} + +?> \ No newline at end of file From f21f05e8749f0914607550b2379801e31bc0d7b1 Mon Sep 17 00:00:00 2001 From: xisi Date: Fri, 24 Jan 2014 22:02:51 -0500 Subject: [PATCH 03/30] pushing to start core rebuild --- public/include/classes/tokentype.class.php | 12 +++++++++ tests/bootstrap.php | 15 +++++++++++ tests/config.php | 3 +++ tests/phpunit.xml | 3 +++ .../securityregress/Security_CSRFToken.php | 1 - .../unit/securityregress/Security_Tokens.php | 25 +++++++++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 tests/unit/securityregress/Security_Tokens.php diff --git a/public/include/classes/tokentype.class.php b/public/include/classes/tokentype.class.php index 8befe7f0..c35dd84a 100644 --- a/public/include/classes/tokentype.class.php +++ b/public/include/classes/tokentype.class.php @@ -36,6 +36,18 @@ class Token_Type Extends Base { return $result->fetch_all(MYSQLI_ASSOC); return $this->sqlError(); } + + /** + * Fetch all tokens - used for unit tests + * @param none + * @return array All tokentypes + **/ + public function getAll() { + $stmt = $this->mysqli->prepare("SELECT * FROM $this->table"); + if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + return $this->sqlError(); + } } $tokentype = new Token_Type(); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 3aa4c274..b11e7c48 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -20,4 +20,19 @@ require_once(BASEPATH . 'include/autoloader.inc.php'); require_once("PHPUnit/Autoload.php"); +/* + * apache2* libapache2-mod-php5* mysql-server* php-codecoverage* + php-codesniffer* php-file-iterator* php-gettext* php-pear* php-symfony-yaml* + php-text-template* php-timer* php-token-stream* php5* php5-cli* + php5-mysqlnd* phpmyadmin* phppgadmin* phpunit* phpunit-mock-object* + sudo apt-get install mysql-server apache2 memcached php5-memcached php5-mysqlnd php5-curl php5-json php5-cli libapache2-mod-php5 phpmyadmin phpunit phpunit-mock-object + */ + +// your db connection setup +class DBConnection { + public function __construct($config) { + return new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); + } +} + ?> \ No newline at end of file diff --git a/tests/config.php b/tests/config.php index cbcdb1af..82f2ef67 100644 --- a/tests/config.php +++ b/tests/config.php @@ -7,4 +7,7 @@ define('BASEPATH', '/var/www/php-mpos-allbranches/php-mpos/public/'); // 0 = dist, 1 = real define('DIST_OR_REAL_CONFIG', 1); +// because php cli defaults are shit, the socket might be wrong +ini_set('mysqli.default_socket', '/var/run/mysqld/mysqld.sock'); + ?> \ No newline at end of file diff --git a/tests/phpunit.xml b/tests/phpunit.xml index 513c0d17..5a0c3765 100644 --- a/tests/phpunit.xml +++ b/tests/phpunit.xml @@ -9,5 +9,8 @@ unit/securityregress/Security_Sessions.php + + unit/securityregress/Security_Tokens.php + \ No newline at end of file diff --git a/tests/unit/securityregress/Security_CSRFToken.php b/tests/unit/securityregress/Security_CSRFToken.php index beb01644..a3a0d7f5 100644 --- a/tests/unit/securityregress/Security_CSRFToken.php +++ b/tests/unit/securityregress/Security_CSRFToken.php @@ -14,7 +14,6 @@ class Security_CSRFToken extends PHPUnit_Framework_Testcase { $created_token = $csrftoken->getBasic($user->getCurrentIP(), 'test-token'); $test_token = $csrftoken->checkBasic($user->getCurrentIP(), 'test-token', $created_token); $this->assertTrue($test_token); - $this->assertAttributeEquals($csrftoken->valid, true); } /** diff --git a/tests/unit/securityregress/Security_Tokens.php b/tests/unit/securityregress/Security_Tokens.php new file mode 100644 index 00000000..4ff8d967 --- /dev/null +++ b/tests/unit/securityregress/Security_Tokens.php @@ -0,0 +1,25 @@ +getAll(); + + foreach ($token_types as $tt) { + // create + $create_token = $oToken->createToken($tt['name'], 1); + $this->assertStringMatchesFormat('%x', $create_token); + $this->assertGreaterThan(16, strlen($create_token)); + } + } +} + +?> \ No newline at end of file From 9dcb855b34792e92f41e340033482a65223282d5 Mon Sep 17 00:00:00 2001 From: xisi Date: Fri, 24 Jan 2014 23:35:35 -0500 Subject: [PATCH 04/30] strict class, trying to figure out why edit account doesnt work --- public/include/autoloader.inc.php | 4 ++ public/include/classes/strict.class.php | 45 +++++++++++++++++++++++ public/include/database.inc.php | 8 +++- public/include/pages/account/edit.inc.php | 2 +- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 public/include/classes/strict.class.php diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 5bf2652f..2359446e 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -9,6 +9,10 @@ if (empty($config['algorithm']) || $config['algorithm'] == 'scrypt') { } else { $config['target_bits'] = 32; } +if ($config['strict']) { + require_once(CLASS_DIR . '/strict.class.php'); +} + // Default classes require_once(CLASS_DIR . '/debug.class.php'); require_once(INCLUDE_DIR . '/lib/KLogger.php'); diff --git a/public/include/classes/strict.class.php b/public/include/classes/strict.class.php new file mode 100644 index 00000000..b81a9211 --- /dev/null +++ b/public/include/classes/strict.class.php @@ -0,0 +1,45 @@ + \ No newline at end of file diff --git a/public/include/database.inc.php b/public/include/database.inc.php index edfa8ca5..a11d1748 100644 --- a/public/include/database.inc.php +++ b/public/include/database.inc.php @@ -5,7 +5,12 @@ if (!defined('SECURITY')) die('Hacking attempt'); // Instantiate class, we are using mysqlng -$mysqli = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); +if ($config['strict']) { + $mysqli = new mysqli_strict($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']) or die('couldnt load class'); + //$mysqli = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); +} else { + +} // Check if read-only and quit if it is on if ($mysqli->query('/* MYSQLND_MS_MASTER_SWITCH */SELECT @@global.read_only AS read_only')->fetch_object()->read_only == 1) { @@ -16,4 +21,5 @@ if ($mysqli->query('/* MYSQLND_MS_MASTER_SWITCH */SELECT @@global.read_only AS r if (mysqli_connect_errno()) { die("Failed to connect to database"); } + ?> diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php index ed058175..1d01ee11 100644 --- a/public/include/pages/account/edit.inc.php +++ b/public/include/pages/account/edit.inc.php @@ -1,5 +1,5 @@ Date: Sat, 25 Jan 2014 00:39:57 -0500 Subject: [PATCH 05/30] blah blah --- public/include/autoloader.inc.php | 11 +- public/include/classes/api.class.php | 4 +- public/include/classes/base.class.php | 5 +- public/include/classes/bitcoin.class.php | 4 +- .../include/classes/bitcoinwrapper.class.php | 5 +- public/include/classes/block.class.php | 4 +- public/include/classes/csrftoken.class.php | 4 +- public/include/classes/debug.class.php | 5 +- public/include/classes/invitation.class.php | 4 +- public/include/classes/mail.class.php | 5 +- public/include/classes/memcache_ad.class.php | 73 ++++++++++++ public/include/classes/memcached.class.php | 4 +- public/include/classes/monitoring.class.php | 4 +- public/include/classes/news.class.php | 5 +- public/include/classes/notification.class.php | 5 +- public/include/classes/payout.class.php | 4 +- public/include/classes/roundstats.class.php | 5 +- public/include/classes/setting.class.php | 4 +- public/include/classes/share.class.php | 5 +- public/include/classes/statistics.class.php | 5 +- public/include/classes/statscache.class.php | 5 +- public/include/classes/strict.class.php | 109 +++++++++++++++++- public/include/classes/template.class.php | 5 +- public/include/classes/token.class.php | 4 +- public/include/classes/tokentype.class.php | 5 +- public/include/classes/tools.class.php | 5 +- public/include/classes/transaction.class.php | 5 +- public/include/classes/user.class.php | 7 +- public/include/classes/worker.class.php | 4 +- public/include/config/admin_settings.inc.php | 4 +- public/include/config/error_codes.inc.php | 4 +- public/include/config/global.inc.dist.php | 17 ++- public/include/config/memcache_keys.inc.php | 4 +- public/include/database.inc.php | 10 +- public/include/pages/about.inc.php | 5 +- public/include/pages/about/api.inc.php | 4 +- public/include/pages/about/donors.inc.php | 4 +- public/include/pages/about/pool.inc.php | 5 +- public/include/pages/about/pplns.inc.php | 5 +- public/include/pages/account.inc.php | 4 +- public/include/pages/account/confirm.inc.php | 4 +- public/include/pages/account/edit.inc.php | 20 ++-- .../include/pages/account/invitations.inc.php | 4 +- .../pages/account/notifications.inc.php | 3 +- public/include/pages/account/qrcode.inc.php | 3 +- .../pages/account/reset_failed.inc.php | 4 +- .../pages/account/transactions.inc.php | 3 +- public/include/pages/account/unlock.inc.php | 4 +- public/include/pages/account/workers.inc.php | 3 +- public/include/pages/admin.inc.php | 4 +- public/include/pages/admin/dashboard.inc.php | 4 +- public/include/pages/admin/monitoring.inc.php | 4 +- public/include/pages/admin/news.inc.php | 4 +- public/include/pages/admin/news_edit.inc.php | 4 +- .../include/pages/admin/poolworkers.inc.php | 3 +- public/include/pages/admin/reports.inc.php | 4 +- public/include/pages/admin/settings.inc.php | 4 +- public/include/pages/admin/templates.inc.php | 4 +- .../include/pages/admin/transactions.inc.php | 4 +- public/include/pages/admin/user.inc.php | 4 +- public/include/pages/admin/wallet.inc.php | 4 +- public/include/pages/api.inc.php | 4 +- .../include/pages/api/getblockcount.inc.php | 4 +- .../include/pages/api/getblocksfound.inc.php | 4 +- .../include/pages/api/getblockstats.inc.php | 4 +- .../pages/api/getcronjobstatus.inc.php | 4 +- .../pages/api/getcurrentworkers.inc.php | 4 +- .../pages/api/getdashboarddata.inc.php | 4 +- .../include/pages/api/getdifficulty.inc.php | 4 +- .../pages/api/getestimatedtime.inc.php | 4 +- .../pages/api/gethourlyhashrates.inc.php | 4 +- .../include/pages/api/getnavbardata.inc.php | 4 +- .../include/pages/api/getpoolhashrate.inc.php | 4 +- public/include/pages/api/getpoolinfo.inc.php | 4 +- .../pages/api/getpoolsharerate.inc.php | 4 +- .../include/pages/api/getpoolstatus.inc.php | 4 +- .../pages/api/gettimesincelastblock.inc.php | 4 +- .../pages/api/gettopcontributors.inc.php | 4 +- .../include/pages/api/getuserbalance.inc.php | 4 +- .../include/pages/api/getuserhashrate.inc.php | 4 +- .../pages/api/getusersharerate.inc.php | 4 +- .../include/pages/api/getuserstatus.inc.php | 4 +- .../pages/api/getusertransactions.inc.php | 4 +- .../include/pages/api/getuserworkers.inc.php | 4 +- public/include/pages/api/public.inc.php | 4 +- public/include/pages/contactform.inc.php | 4 +- .../pages/contactform/contactform.inc.php | 4 +- public/include/pages/dashboard.inc.php | 4 +- public/include/pages/error.inc.php | 5 +- public/include/pages/error/404.inc.php | 5 +- public/include/pages/error/ratelimit.inc.php | 6 + public/include/pages/gettingstarted.inc.php | 5 +- public/include/pages/home.inc.php | 4 +- public/include/pages/login.inc.php | 4 +- public/include/pages/logout.inc.php | 13 ++- public/include/pages/news.inc.php | 4 +- public/include/pages/password.inc.php | 5 +- public/include/pages/password/change.inc.php | 5 +- public/include/pages/password/reset.inc.php | 4 +- public/include/pages/register.inc.php | 4 +- .../include/pages/register/register.inc.php | 3 +- public/include/pages/statistics.inc.php | 5 +- .../pages/statistics/blockfinder.inc.php | 4 +- .../include/pages/statistics/blocks.inc.php | 4 +- .../include/pages/statistics/graphs.inc.php | 4 +- public/include/pages/statistics/pool.inc.php | 4 +- public/include/pages/statistics/round.inc.php | 4 +- .../include/pages/statistics/uptime.inc.php | 4 +- public/include/pages/tac.inc.php | 3 +- public/include/pages/tacpop.inc.php | 3 +- public/include/smarty.inc.php | 5 +- public/include/smarty_globals.inc.php | 4 +- public/include/version.inc.php | 6 +- public/index.php | 85 +++++++++++--- .../mpos/error/ratelimit/default.tpl | 6 + 115 files changed, 405 insertions(+), 386 deletions(-) create mode 100644 public/include/classes/memcache_ad.class.php create mode 100644 public/include/pages/error/ratelimit.inc.php create mode 100644 public/templates/mpos/error/ratelimit/default.tpl diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 2359446e..70871ac6 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -1,7 +1,6 @@ Set a new SECURITY value to continue") : 0; +$defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // SHA/Scrypt check if (empty($config['algorithm']) || $config['algorithm'] == 'scrypt') { @@ -9,13 +8,13 @@ if (empty($config['algorithm']) || $config['algorithm'] == 'scrypt') { } else { $config['target_bits'] = 32; } -if ($config['strict']) { - require_once(CLASS_DIR . '/strict.class.php'); -} // Default classes require_once(CLASS_DIR . '/debug.class.php'); require_once(INCLUDE_DIR . '/lib/KLogger.php'); +if ($config['strict']) { + require_once(CLASS_DIR . '/strict.class.php'); +} require_once(INCLUDE_DIR . '/database.inc.php'); require_once(INCLUDE_DIR . '/config/memcache_keys.inc.php'); require_once(INCLUDE_DIR . '/config/error_codes.inc.php'); diff --git a/public/include/classes/api.class.php b/public/include/classes/api.class.php index 336ba2bc..be57fbbf 100644 --- a/public/include/classes/api.class.php +++ b/public/include/classes/api.class.php @@ -1,7 +1,5 @@ '', + 'last_hit' => 0, + 'last_flush' => 0, + 'hits_since_flush' => 0 + ); + public $rate_limit_this_request = false; + public function __construct($config, $userORip, $request, $mcSettings) { + if (PHP_OS == 'WINNT') { + require_once('memcached.class.php'); + } + $this->cache = new Memcached(); + $this->cache->addServer($mcSettings['host'], $mcSettings['port']); + // set our config options + $per_page = $config['per_page']; + $flush_sec = $config['flush_seconds']; + $rate_limit = $config['rate_limit']; + unset($config); + // prep stuff we need to check this request + $key_md5 = substr(md5($userORip), 0, 4); + $request_md5 = substr(md5($request), 0, 4); + $request_key = $mcSettings['keyprefix'].self::$key.$key_md5."_".$request_md5."_".$per_page; + $request_data = $this->cache->get($request_key); + $now = time(); + // check the request + if (is_array($request_data)) { + // this request key already exists, update it + $request_data['ident'] = $key_md5; + $request_data['last_hit'] = $now; + $request_data['hits_since_flush'] += 1; + // not rate limited yet, update the rest of the object + if ($request_data['hits_since_flush'] < $rate_limit) { + if (($request_data['last_flush'] + $flush_sec) <= $now || ($request_data['last_hit'] + $flush_sec) <= $now) { + // needs to be flushed + $request_data['hits_since_flush'] = 0; + $request_data['last_hit'] = 0; + $request_data['last_flush'] = $now; + // update the object + $this->cache->set($request_key, $request_data, $flush_sec); + $this->rate_limit_this_request = false; + } else { + // no flush, just update + $this->cache->set($request_key, $request_data, $flush_sec); + $this->rate_limit_this_request = false; + } + } else { + // too many hits, we should rate limit this + $this->rate_limit_this_request = true; + } + } else { + // doesn't exist for this request_key, create one + $new_data = self::$request_model; + $new_data['ident'] = $key_md5; + $new_data['last_hit'] = time(); + $new_data['hits_since_flush'] = 1; + $new_data['last_flush'] = $now; + $this->cache->set($request_key, $new_data, $flush_sec); + $this->rate_limit_this_request = false; + } + } + public function rateLimitRequest() { + return $this->rate_limit_this_request; + } +} + +?> \ No newline at end of file diff --git a/public/include/classes/memcached.class.php b/public/include/classes/memcached.class.php index 2f431337..55a66c67 100644 --- a/public/include/classes/memcached.class.php +++ b/public/include/classes/memcached.class.php @@ -1,7 +1,5 @@ bind_address !== $this->server_http_host) { + return false; + } else { + return true; + } + } + + public function verify_client($ip) { + if ($this->started && $this->memcache_handle !== null && $this->verify_server()) { + $read_client = $this->memcache_handle->get(md5((string)$ip)); + if ($read_client !== false) { + if (md5((string)$ip) !== $read_client[0]) { + return false; + } else { + return true; + } + } else { + return false; + } + } else { + return false; + } + } + + public function update_client($ip) { + if ($this->started && $this->memcache_handle !== null && $this->verify_client($ip)) { + $this->memcache_handle->set(md5((string)$ip), array($this->current_session_id, time())); + } + } + + public function set_cookie() { + if ($this->started && $this->memcache_handle !== null && $this->verify_server() && $this->verify_client($ip)) { + @setcookie(session_name(), session_id(), $this->config_dura, $this->config_path, $this->config_domain, $this->config_secure, $this->config_httponly); + } + } + + public function destroy_session($ip) { + if ($this->started && $this->verify_server() && $this->verify_client($ip)) { + $this->memcache_handle->delete(md5((string)$ip)); + if (ini_get('session.use_cookies')) { + setcookie(session_name(), '', time() - 42000, $config_path, $config_domain, $config_secure, $config_httponly); + } + session_destroy(); + session_regenerate_id(true); + } + } public function create_session($ip) { - // TODO: put memcache rate limiting into here + if (!$this->verify_server()) { + return false; + } else { + $session_start = @session_start(); + if (!$session_start) { + session_destroy(); + session_regenerate_id(true); + session_start(); + $this->update_client($ip); + $this->started = true; + $this->current_session_id = session_id(); + $this->set_cookie(); + return true; + } else { + if ($this->verify_server() && $this->verify_client($ip)) { + $this->update_client($ip); + return true; + } + } + } + } + + public function __construct($config, $server_host) { + $this->config_dura = $config['cookie']['duration']; + $this->config_path = $config['cookie']['path']; + $this->config_domain = $config['cookie']['domain']; + $this->config_secure = $config['cookie']['secure']; + $this->config_httponly = $config['cookie']['httponly']; + if ($config['strict__enforce_ssl']) $config['strict__bind_protocol'] = 'https'; + $this->bind_address = $config['strict__bind_protocol']."://".$config['strict__bind_host'].":".$config['strict__bind_port']; + $this->server_http_host = $config['strict__bind_protocol']."://".$_SERVER['HTTP_HOST'].":".$config['strict__bind_port']; + unset($config); + $this->set_cookie_params((time()+$this->config_dura), $this->config_path, $this->config_domain, $this->config_secure, $this->config_httponly); } } @@ -30,11 +129,11 @@ class mysqli_strict extends mysqli { break; case 'd': $return_dbl = filter_var($acopy[$i], FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE); - return ($return_dbl !== null) ? (double)$return_dbl : false; + return ($return_dbl !== null) ? (float)$return_dbl : false; break; case 'b': $return_bool = filter_var($acopy[$i], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); - return ($return_bool !== null) ? (boolean)$return_bool : false; + return ($return_bool !== null) ? (bool)$return_bool : false; break; } } diff --git a/public/include/classes/template.class.php b/public/include/classes/template.class.php index fe03fe7b..b297c528 100644 --- a/public/include/classes/template.class.php +++ b/public/include/classes/template.class.php @@ -1,8 +1,5 @@ getThemes(); diff --git a/public/include/config/error_codes.inc.php b/public/include/config/error_codes.inc.php index 9083cf3d..50c4db24 100644 --- a/public/include/config/error_codes.inc.php +++ b/public/include/config/error_codes.inc.php @@ -1,7 +1,5 @@ assign("CONTENT", "default.tpl"); diff --git a/public/include/pages/about/api.inc.php b/public/include/pages/about/api.inc.php index d0eb55e7..ac4117c0 100644 --- a/public/include/pages/about/api.inc.php +++ b/public/include/pages/about/api.inc.php @@ -1,7 +1,5 @@ assign("CONTENT", "default.tpl"); diff --git a/public/include/pages/about/donors.inc.php b/public/include/pages/about/donors.inc.php index 0d4213f7..2e20f761 100644 --- a/public/include/pages/about/donors.inc.php +++ b/public/include/pages/about/donors.inc.php @@ -1,7 +1,5 @@ getValue('disable_donors')) { $_SESSION['POPUP'][] = array('CONTENT' => 'Donors are currently disabled. Please try again later.', 'TYPE' => 'errormsg'); diff --git a/public/include/pages/about/pool.inc.php b/public/include/pages/about/pool.inc.php index 20c860f0..0450f7ef 100644 --- a/public/include/pages/about/pool.inc.php +++ b/public/include/pages/about/pool.inc.php @@ -1,8 +1,5 @@ getValue('disable_about')) { $_SESSION['POPUP'][] = array('CONTENT' => 'Donors are currently disabled. Please try again later.', 'TYPE' => 'errormsg'); diff --git a/public/include/pages/about/pplns.inc.php b/public/include/pages/about/pplns.inc.php index aecab054..ac4117c0 100644 --- a/public/include/pages/about/pplns.inc.php +++ b/public/include/pages/about/pplns.inc.php @@ -1,8 +1,5 @@ assign("CONTENT", "default.tpl"); diff --git a/public/include/pages/account.inc.php b/public/include/pages/account.inc.php index 9e43518e..f3ce16c5 100644 --- a/public/include/pages/account.inc.php +++ b/public/include/pages/account.inc.php @@ -1,7 +1,5 @@ isAuthenticated()) { // Tempalte specifics diff --git a/public/include/pages/account/confirm.inc.php b/public/include/pages/account/confirm.inc.php index 829abcb7..6d175281 100644 --- a/public/include/pages/account/confirm.inc.php +++ b/public/include/pages/account/confirm.inc.php @@ -1,7 +1,5 @@ isAuthenticated() && $config['twofactor']['enabled']) { (!empty($wfprep_sent) && empty($wfprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['wf'], 'TYPE' => 'success'):""; (!empty($cpprep_sent) && !empty($cpprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $cpprep_sent, 'TYPE' => 'success'):""; (!empty($cpprep_sent) && empty($cpprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['cp'], 'TYPE' => 'success'):""; + // two-factor stuff + $smarty->assign("CHANGEPASSUNLOCKED", $cp_editable); + $smarty->assign("WITHDRAWUNLOCKED", $wf_editable); + $smarty->assign("DETAILSUNLOCKED", $ea_editable); + $smarty->assign("CHANGEPASSSENT", $cp_sent); + $smarty->assign("WITHDRAWSENT", $wf_sent); + $smarty->assign("DETAILSSENT", $ea_sent); } -// two-factor stuff -$smarty->assign("CHANGEPASSUNLOCKED", $cp_editable); -$smarty->assign("WITHDRAWUNLOCKED", $wf_editable); -$smarty->assign("DETAILSUNLOCKED", $ea_editable); -$smarty->assign("CHANGEPASSSENT", $cp_sent); -$smarty->assign("WITHDRAWSENT", $wf_sent); -$smarty->assign("DETAILSSENT", $ea_sent); + $smarty->assign("DONATE_THRESHOLD", $config['donate_threshold']); // Tempalte specifics diff --git a/public/include/pages/account/invitations.inc.php b/public/include/pages/account/invitations.inc.php index 0ceb15a8..4020cfd1 100644 --- a/public/include/pages/account/invitations.inc.php +++ b/public/include/pages/account/invitations.inc.php @@ -1,7 +1,5 @@ isAuthenticated()) { if (!$setting->getValue('disable_invitations')) { diff --git a/public/include/pages/account/notifications.inc.php b/public/include/pages/account/notifications.inc.php index 0d0fe7e4..4b180f02 100644 --- a/public/include/pages/account/notifications.inc.php +++ b/public/include/pages/account/notifications.inc.php @@ -1,7 +1,6 @@ isAuthenticated()) { if ($setting->getValue('disable_notifications') == 1) { $_SESSION['POPUP'][] = array('CONTENT' => 'Notification system disabled by admin.', 'TYPE' => 'info'); diff --git a/public/include/pages/account/qrcode.inc.php b/public/include/pages/account/qrcode.inc.php index a6543dc5..3171ded7 100644 --- a/public/include/pages/account/qrcode.inc.php +++ b/public/include/pages/account/qrcode.inc.php @@ -1,6 +1,5 @@ isAuthenticated()) $smarty->assign("CONTENT", "default.tpl"); ?> diff --git a/public/include/pages/account/reset_failed.inc.php b/public/include/pages/account/reset_failed.inc.php index ef30938f..97a08239 100644 --- a/public/include/pages/account/reset_failed.inc.php +++ b/public/include/pages/account/reset_failed.inc.php @@ -1,7 +1,5 @@ isAuthenticated()) { // Reset failed login counter diff --git a/public/include/pages/account/transactions.inc.php b/public/include/pages/account/transactions.inc.php index 72534881..4509b399 100644 --- a/public/include/pages/account/transactions.inc.php +++ b/public/include/pages/account/transactions.inc.php @@ -1,7 +1,6 @@ isAuthenticated()) { $iLimit = 30; empty($_REQUEST['start']) ? $start = 0 : $start = $_REQUEST['start']; diff --git a/public/include/pages/account/unlock.inc.php b/public/include/pages/account/unlock.inc.php index b9d5763b..71c400d1 100644 --- a/public/include/pages/account/unlock.inc.php +++ b/public/include/pages/account/unlock.inc.php @@ -1,7 +1,5 @@ isAuthenticated()) { switch (@$_REQUEST['do']) { diff --git a/public/include/pages/admin.inc.php b/public/include/pages/admin.inc.php index 40abecde..b5067a9f 100644 --- a/public/include/pages/admin.inc.php +++ b/public/include/pages/admin.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/dashboard.inc.php b/public/include/pages/admin/dashboard.inc.php index d5de5f7b..572914f9 100644 --- a/public/include/pages/admin/dashboard.inc.php +++ b/public/include/pages/admin/dashboard.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/monitoring.inc.php b/public/include/pages/admin/monitoring.inc.php index 08efaee4..e720f776 100644 --- a/public/include/pages/admin/monitoring.inc.php +++ b/public/include/pages/admin/monitoring.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/news.inc.php b/public/include/pages/admin/news.inc.php index df0bb2fc..36734294 100644 --- a/public/include/pages/admin/news.inc.php +++ b/public/include/pages/admin/news.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/news_edit.inc.php b/public/include/pages/admin/news_edit.inc.php index 81cfcb56..8549533b 100644 --- a/public/include/pages/admin/news_edit.inc.php +++ b/public/include/pages/admin/news_edit.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/poolworkers.inc.php b/public/include/pages/admin/poolworkers.inc.php index 814d6c07..24cb675c 100644 --- a/public/include/pages/admin/poolworkers.inc.php +++ b/public/include/pages/admin/poolworkers.inc.php @@ -1,6 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/reports.inc.php b/public/include/pages/admin/reports.inc.php index 5225461c..3139234c 100644 --- a/public/include/pages/admin/reports.inc.php +++ b/public/include/pages/admin/reports.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/settings.inc.php b/public/include/pages/admin/settings.inc.php index fe9bc380..6fb477ea 100644 --- a/public/include/pages/admin/settings.inc.php +++ b/public/include/pages/admin/settings.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/templates.inc.php b/public/include/pages/admin/templates.inc.php index b3c101ea..8f67611d 100644 --- a/public/include/pages/admin/templates.inc.php +++ b/public/include/pages/admin/templates.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/transactions.inc.php b/public/include/pages/admin/transactions.inc.php index 7e95092e..37afac7b 100644 --- a/public/include/pages/admin/transactions.inc.php +++ b/public/include/pages/admin/transactions.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php index 955d9cd8..5971dc9a 100644 --- a/public/include/pages/admin/user.inc.php +++ b/public/include/pages/admin/user.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/admin/wallet.inc.php b/public/include/pages/admin/wallet.inc.php index c7e821c8..909d05ef 100644 --- a/public/include/pages/admin/wallet.inc.php +++ b/public/include/pages/admin/wallet.inc.php @@ -1,7 +1,5 @@ isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { diff --git a/public/include/pages/api.inc.php b/public/include/pages/api.inc.php index c85ada42..01cd20f5 100644 --- a/public/include/pages/api.inc.php +++ b/public/include/pages/api.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getblockcount.inc.php b/public/include/pages/api/getblockcount.inc.php index 978a7142..5000afdd 100644 --- a/public/include/pages/api/getblockcount.inc.php +++ b/public/include/pages/api/getblockcount.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getblocksfound.inc.php b/public/include/pages/api/getblocksfound.inc.php index de2918f6..d280b266 100644 --- a/public/include/pages/api/getblocksfound.inc.php +++ b/public/include/pages/api/getblocksfound.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getblockstats.inc.php b/public/include/pages/api/getblockstats.inc.php index 9d6200d5..725ad628 100644 --- a/public/include/pages/api/getblockstats.inc.php +++ b/public/include/pages/api/getblockstats.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getcronjobstatus.inc.php b/public/include/pages/api/getcronjobstatus.inc.php index 8dab4f09..b932b8dd 100644 --- a/public/include/pages/api/getcronjobstatus.inc.php +++ b/public/include/pages/api/getcronjobstatus.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getcurrentworkers.inc.php b/public/include/pages/api/getcurrentworkers.inc.php index 837b75ef..4b142822 100644 --- a/public/include/pages/api/getcurrentworkers.inc.php +++ b/public/include/pages/api/getcurrentworkers.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getdashboarddata.inc.php b/public/include/pages/api/getdashboarddata.inc.php index b5a73801..9f7c6844 100644 --- a/public/include/pages/api/getdashboarddata.inc.php +++ b/public/include/pages/api/getdashboarddata.inc.php @@ -1,7 +1,5 @@ getValue('disable_dashboard_api')) { diff --git a/public/include/pages/api/getdifficulty.inc.php b/public/include/pages/api/getdifficulty.inc.php index 95805548..7cc88766 100644 --- a/public/include/pages/api/getdifficulty.inc.php +++ b/public/include/pages/api/getdifficulty.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getestimatedtime.inc.php b/public/include/pages/api/getestimatedtime.inc.php index 91ed811d..5d529545 100644 --- a/public/include/pages/api/getestimatedtime.inc.php +++ b/public/include/pages/api/getestimatedtime.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/gethourlyhashrates.inc.php b/public/include/pages/api/gethourlyhashrates.inc.php index d9dfea0a..c6c7f670 100644 --- a/public/include/pages/api/gethourlyhashrates.inc.php +++ b/public/include/pages/api/gethourlyhashrates.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getnavbardata.inc.php b/public/include/pages/api/getnavbardata.inc.php index a412f984..f043a7c1 100644 --- a/public/include/pages/api/getnavbardata.inc.php +++ b/public/include/pages/api/getnavbardata.inc.php @@ -1,7 +1,5 @@ getValue('disable_navbar_api')) { diff --git a/public/include/pages/api/getpoolhashrate.inc.php b/public/include/pages/api/getpoolhashrate.inc.php index a5985d44..bb6fe8ea 100644 --- a/public/include/pages/api/getpoolhashrate.inc.php +++ b/public/include/pages/api/getpoolhashrate.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getpoolinfo.inc.php b/public/include/pages/api/getpoolinfo.inc.php index 66d87004..217a2224 100644 --- a/public/include/pages/api/getpoolinfo.inc.php +++ b/public/include/pages/api/getpoolinfo.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getpoolsharerate.inc.php b/public/include/pages/api/getpoolsharerate.inc.php index a55654be..8b8977e5 100644 --- a/public/include/pages/api/getpoolsharerate.inc.php +++ b/public/include/pages/api/getpoolsharerate.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getpoolstatus.inc.php b/public/include/pages/api/getpoolstatus.inc.php index ea053dcb..a364a45b 100644 --- a/public/include/pages/api/getpoolstatus.inc.php +++ b/public/include/pages/api/getpoolstatus.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/gettimesincelastblock.inc.php b/public/include/pages/api/gettimesincelastblock.inc.php index c0de01f8..e586beac 100644 --- a/public/include/pages/api/gettimesincelastblock.inc.php +++ b/public/include/pages/api/gettimesincelastblock.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/gettopcontributors.inc.php b/public/include/pages/api/gettopcontributors.inc.php index 0b22faee..e5bc7e6f 100644 --- a/public/include/pages/api/gettopcontributors.inc.php +++ b/public/include/pages/api/gettopcontributors.inc.php @@ -1,7 +1,5 @@ checkAccess($user->checkApiKey($_REQUEST['api_key']), @$_REQUEST['id']); diff --git a/public/include/pages/api/getuserbalance.inc.php b/public/include/pages/api/getuserbalance.inc.php index d91c6865..e46901bb 100644 --- a/public/include/pages/api/getuserbalance.inc.php +++ b/public/include/pages/api/getuserbalance.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getuserhashrate.inc.php b/public/include/pages/api/getuserhashrate.inc.php index 1b1d5250..13f61a8c 100644 --- a/public/include/pages/api/getuserhashrate.inc.php +++ b/public/include/pages/api/getuserhashrate.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getusersharerate.inc.php b/public/include/pages/api/getusersharerate.inc.php index c1edb01e..86b3c762 100644 --- a/public/include/pages/api/getusersharerate.inc.php +++ b/public/include/pages/api/getusersharerate.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getuserstatus.inc.php b/public/include/pages/api/getuserstatus.inc.php index c17bb77f..df514c9a 100644 --- a/public/include/pages/api/getuserstatus.inc.php +++ b/public/include/pages/api/getuserstatus.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getusertransactions.inc.php b/public/include/pages/api/getusertransactions.inc.php index 08517d2d..403ff929 100644 --- a/public/include/pages/api/getusertransactions.inc.php +++ b/public/include/pages/api/getusertransactions.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/getuserworkers.inc.php b/public/include/pages/api/getuserworkers.inc.php index 089e227d..69a8122a 100644 --- a/public/include/pages/api/getuserworkers.inc.php +++ b/public/include/pages/api/getuserworkers.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/api/public.inc.php b/public/include/pages/api/public.inc.php index f465d1a8..c6b128d6 100644 --- a/public/include/pages/api/public.inc.php +++ b/public/include/pages/api/public.inc.php @@ -1,7 +1,5 @@ isActive(); diff --git a/public/include/pages/contactform.inc.php b/public/include/pages/contactform.inc.php index b961cfb2..fdbf26da 100644 --- a/public/include/pages/contactform.inc.php +++ b/public/include/pages/contactform.inc.php @@ -1,7 +1,5 @@ getValue('disable_contactform')) { $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is currently disabled. Please try again later.', 'TYPE' => 'errormsg'); diff --git a/public/include/pages/contactform/contactform.inc.php b/public/include/pages/contactform/contactform.inc.php index 19916321..f0aa6f9f 100644 --- a/public/include/pages/contactform/contactform.inc.php +++ b/public/include/pages/contactform/contactform.inc.php @@ -1,7 +1,5 @@ getValue('recaptcha_enabled')) { // Load re-captcha specific data diff --git a/public/include/pages/dashboard.inc.php b/public/include/pages/dashboard.inc.php index f835f6e7..7047cfb8 100644 --- a/public/include/pages/dashboard.inc.php +++ b/public/include/pages/dashboard.inc.php @@ -1,7 +1,5 @@ isAuthenticated()) { if (! $interval = $setting->getValue('statistics_ajax_data_interval')) $interval = 300; diff --git a/public/include/pages/error.inc.php b/public/include/pages/error.inc.php index aecab054..ac4117c0 100644 --- a/public/include/pages/error.inc.php +++ b/public/include/pages/error.inc.php @@ -1,8 +1,5 @@ assign("CONTENT", "default.tpl"); diff --git a/public/include/pages/error/404.inc.php b/public/include/pages/error/404.inc.php index aecab054..ac4117c0 100644 --- a/public/include/pages/error/404.inc.php +++ b/public/include/pages/error/404.inc.php @@ -1,8 +1,5 @@ assign("CONTENT", "default.tpl"); diff --git a/public/include/pages/error/ratelimit.inc.php b/public/include/pages/error/ratelimit.inc.php new file mode 100644 index 00000000..89cd2920 --- /dev/null +++ b/public/include/pages/error/ratelimit.inc.php @@ -0,0 +1,6 @@ +assign("CONTENT", "default.tpl"); +?> \ No newline at end of file diff --git a/public/include/pages/gettingstarted.inc.php b/public/include/pages/gettingstarted.inc.php index e7de19b8..b6f63bc7 100644 --- a/public/include/pages/gettingstarted.inc.php +++ b/public/include/pages/gettingstarted.inc.php @@ -1,8 +1,5 @@ assign("SITESTRATUMURL", $config['gettingstarted']['stratumurl']); $smarty->assign("SITESTRATUMPORT", $config['gettingstarted']['stratumport']); diff --git a/public/include/pages/home.inc.php b/public/include/pages/home.inc.php index 99c01c04..72a29af7 100644 --- a/public/include/pages/home.inc.php +++ b/public/include/pages/home.inc.php @@ -1,7 +1,5 @@ getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins')) { diff --git a/public/include/pages/logout.inc.php b/public/include/pages/logout.inc.php index 30425851..457c7b50 100644 --- a/public/include/pages/logout.inc.php +++ b/public/include/pages/logout.inc.php @@ -1,10 +1,11 @@ logoutUser(); +if ($config['strict']) { + $session->destroy_session($_SERVER['REMOTE_ADDR']); + $user->logoutUser(); +} else { + $user->logoutUser(); +} $smarty->assign("CONTENT", "default.tpl"); ?> diff --git a/public/include/pages/news.inc.php b/public/include/pages/news.inc.php index 6e7a90c7..51630e9b 100644 --- a/public/include/pages/news.inc.php +++ b/public/include/pages/news.inc.php @@ -1,7 +1,5 @@ assign("CONTENT", "default.tpl"); diff --git a/public/include/pages/password/change.inc.php b/public/include/pages/password/change.inc.php index f622363b..938ed51b 100644 --- a/public/include/pages/password/change.inc.php +++ b/public/include/pages/password/change.inc.php @@ -1,8 +1,5 @@ valid) { if (isset($_POST['do']) && $_POST['do'] == 'resetPassword') { diff --git a/public/include/pages/password/reset.inc.php b/public/include/pages/password/reset.inc.php index 0fa2303d..c06c21b6 100644 --- a/public/include/pages/password/reset.inc.php +++ b/public/include/pages/password/reset.inc.php @@ -1,7 +1,5 @@ valid) { diff --git a/public/include/pages/register.inc.php b/public/include/pages/register.inc.php index 15d077fe..da9ec064 100644 --- a/public/include/pages/register.inc.php +++ b/public/include/pages/register.inc.php @@ -1,7 +1,5 @@ getValue('lock_registration') && $setting->getValue('disable_invitations')) { $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg'); diff --git a/public/include/pages/register/register.inc.php b/public/include/pages/register/register.inc.php index 9f2ad8b6..31afe78d 100644 --- a/public/include/pages/register/register.inc.php +++ b/public/include/pages/register/register.inc.php @@ -1,6 +1,5 @@ getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_registrations')) { diff --git a/public/include/pages/statistics.inc.php b/public/include/pages/statistics.inc.php index 3f63e870..ca100ea4 100644 --- a/public/include/pages/statistics.inc.php +++ b/public/include/pages/statistics.inc.php @@ -1,8 +1,5 @@ isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); diff --git a/public/include/pages/statistics/blockfinder.inc.php b/public/include/pages/statistics/blockfinder.inc.php index f471afdf..6773e920 100644 --- a/public/include/pages/statistics/blockfinder.inc.php +++ b/public/include/pages/statistics/blockfinder.inc.php @@ -1,7 +1,5 @@ isCached('master.tpl', $smarty_cache_key)) { diff --git a/public/include/pages/statistics/blocks.inc.php b/public/include/pages/statistics/blocks.inc.php index 12f034c0..fb580b8f 100644 --- a/public/include/pages/statistics/blocks.inc.php +++ b/public/include/pages/statistics/blocks.inc.php @@ -1,7 +1,5 @@ isCached('master.tpl', $smarty_cache_key)) { diff --git a/public/include/pages/statistics/graphs.inc.php b/public/include/pages/statistics/graphs.inc.php index 575ce36d..f574c1fc 100644 --- a/public/include/pages/statistics/graphs.inc.php +++ b/public/include/pages/statistics/graphs.inc.php @@ -1,7 +1,5 @@ isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); diff --git a/public/include/pages/statistics/pool.inc.php b/public/include/pages/statistics/pool.inc.php index ae42aebc..84fb3546 100644 --- a/public/include/pages/statistics/pool.inc.php +++ b/public/include/pages/statistics/pool.inc.php @@ -1,7 +1,5 @@ can_connect() === true){ diff --git a/public/include/pages/statistics/round.inc.php b/public/include/pages/statistics/round.inc.php index 4e7288d5..064dd3ee 100644 --- a/public/include/pages/statistics/round.inc.php +++ b/public/include/pages/statistics/round.inc.php @@ -1,7 +1,5 @@ isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); diff --git a/public/include/pages/statistics/uptime.inc.php b/public/include/pages/statistics/uptime.inc.php index 81a12799..253ab76c 100644 --- a/public/include/pages/statistics/uptime.inc.php +++ b/public/include/pages/statistics/uptime.inc.php @@ -1,7 +1,5 @@ isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); diff --git a/public/include/pages/tac.inc.php b/public/include/pages/tac.inc.php index de4542b1..cdd3e92d 100644 --- a/public/include/pages/tac.inc.php +++ b/public/include/pages/tac.inc.php @@ -1,6 +1,5 @@ assign("CONTENT", "default.tpl"); ?> diff --git a/public/include/pages/tacpop.inc.php b/public/include/pages/tacpop.inc.php index 86087ec0..16ae6777 100644 --- a/public/include/pages/tacpop.inc.php +++ b/public/include/pages/tacpop.inc.php @@ -1,6 +1,5 @@ diff --git a/public/include/smarty.inc.php b/public/include/smarty.inc.php index ba549af6..b3aa8e7b 100644 --- a/public/include/smarty.inc.php +++ b/public/include/smarty.inc.php @@ -1,8 +1,5 @@ append('Loading Smarty libraries', 2); define('SMARTY_DIR', INCLUDE_DIR . '/smarty/libs/'); diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php index 87dc64e2..bb658cd1 100644 --- a/public/include/smarty_globals.inc.php +++ b/public/include/smarty_globals.inc.php @@ -1,7 +1,5 @@ append('Global smarty variables', 3); diff --git a/public/include/version.inc.php b/public/include/version.inc.php index f1fbcf4b..6206c0a2 100644 --- a/public/include/version.inc.php +++ b/public/include/version.inc.php @@ -1,11 +1,9 @@ getValue('DB_VERSION'); diff --git a/public/index.php b/public/index.php index 30279049..5ad10a73 100644 --- a/public/index.php +++ b/public/index.php @@ -1,5 +1,4 @@ verify_server()) { + $session->create_session($_SERVER['REMOTE_ADDR']); + if ($session->verify_client($_SERVER['REMOTE_ADDR'])) { + $session->update_client($_SERVER['REMOTE_ADDR']); + } + } +} else { + session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); + $session_start = @session_start(); + if (!$session_start) { + session_destroy(); + session_regenerate_id(true); + session_start(); + } + @setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); +} +// Rate limiting +if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $config['strict']) { + require_once(CLASS_DIR . '/memcache_ad.class.php'); + + $skip_check = false; + $per_page = ($config['mc_antidos']['per_page']) ? $_SERVER['QUERY_STRING'] : ''; + // if this is an api call we need to be careful not to time them out for those calls separately + $ajax_call_querystrings = array( + 'page=api&action=getuserbalance', + 'page=api&action=getnavbardata', + 'page=api&action=getdashboarddata', + 'page=api&action=getuserworkers' + ); + // cut off any potential extra get info from querystring and see if it's an ajax call + $is_ajax_call = (in_array(substr($_SERVER['QUERY_STRING'], 0, 32), $ajax_call_querystrings)) ? true : false; + if ($is_ajax_call && $config['mc_antidos']['protect_ajax']) { + $per_page = 'navbar'; + } else if ($is_ajax_call && !$config['mc_antidos']['protect_ajax']) { + // protect isn't on, we'll ignore it + $skip_check = true; + } else if ($config['mc_antidos']['ignore_admins'] && isset($_SESSION['USERDATA']['is_admin']) && $_SESSION['USERDATA']['is_admin']) { + $skip_check = true; + } + if (!$skip_check) { + $session->memcache_handle = new MemcacheAntiDos($config['mc_antidos'], $_SERVER['REMOTE_ADDR'], $per_page, $config['memcache']); + $rate_limit_reached = $session->memcache_handle->rateLimitRequest(); + $error_page = $config['mc_antidos']['error_push_page']; + if ($rate_limit_reached == true) { + if (!is_array($error_page) || count($error_page) < 1 || (empty($error_page['page']) && empty($error_page['action']))) { + die("You are sending too many requests too fast!"); + } else { + $_REQUEST['page'] = $error_page['page']; + $_REQUEST['action'] = (isset($error_page['action']) && !empty($error_page['action'])) ? $error_page['action'] : $_REQUEST['action']; + } + } + } +} + // Create our pages array from existing files if (is_dir(INCLUDE_DIR . '/pages/')) { foreach (glob(INCLUDE_DIR . '/pages/*.inc.php') as $filepath) { @@ -118,4 +175,4 @@ if (!@$supress_master) $smarty->display($master_template, $smarty_cache_key); // Unset any temporary values here unset($_SESSION['POPUP']); -?> +?> \ No newline at end of file diff --git a/public/templates/mpos/error/ratelimit/default.tpl b/public/templates/mpos/error/ratelimit/default.tpl new file mode 100644 index 00000000..7ab5c72b --- /dev/null +++ b/public/templates/mpos/error/ratelimit/default.tpl @@ -0,0 +1,6 @@ +
+

Request rate limit exceeded

+
+

You're sending too many requests too fast!

+
+
\ No newline at end of file From d5f1c97f82c9cf8374fe0adb274fd9a273917c4a Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 26 Jan 2014 08:08:20 -0500 Subject: [PATCH 06/30] fixed check against define like it used to even if SECHASH_CHECK is disabled fixed ajax calls in memcache limiter to use REQUEST page/action rather than QUERY_STRING --- public/index.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/public/index.php b/public/index.php index 5ad10a73..f602a732 100644 --- a/public/index.php +++ b/public/index.php @@ -19,6 +19,7 @@ limitations under the License. // Set a decently long SECURITY key with special chars etc define('SECURITY', '*)WT#&YHfd'); +// Disable the sechash check if you're sure, still checks if SECURITY defined as before define('SECHASH_CHECK', true); // change SECHASH every second, we allow up to 3 sec back for slow servers @@ -27,7 +28,7 @@ if (SECHASH_CHECK) { define('SECHASH', fip()); function cfip() { return (fip()==SECHASH||fip(1)==SECHASH||fip(2)==SECHASH) ? 1 : 0; } } else { - function cfip() { return 1; } + function cfip() { return (defined('SECURITY')) ? 1 : 0; } } // Used for performance calculations @@ -43,8 +44,6 @@ if (!include_once(BASEPATH . 'include/config/global.inc.php')) die('Unable to lo // Our default template to load, pages can overwrite this later $master_template = 'master.tpl'; -// Start a session - // Load Classes, they name defines the $ variable used // We include all needed files here, even though our templates could load them themself require_once(INCLUDE_DIR . '/autoloader.inc.php'); @@ -74,15 +73,20 @@ if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $confi $skip_check = false; $per_page = ($config['mc_antidos']['per_page']) ? $_SERVER['QUERY_STRING'] : ''; // if this is an api call we need to be careful not to time them out for those calls separately - $ajax_call_querystrings = array( - 'page=api&action=getuserbalance', - 'page=api&action=getnavbardata', - 'page=api&action=getdashboarddata', - 'page=api&action=getuserworkers' + $ajax_calls = array( + array('api', 'getuserbalance'), + array('api', 'getnavbardata'), + array('api', 'getdashboarddata'), + array('api', 'getuserworkers') ); - // cut off any potential extra get info from querystring and see if it's an ajax call - $is_ajax_call = (in_array(substr($_SERVER['QUERY_STRING'], 0, 32), $ajax_call_querystrings)) ? true : false; + $iac = 0; + foreach ($ajax_calls as $ac) { + $iac = (@$_REQUEST['page'] == $ac[0] && @$_REQUEST['action'] == $ac[1]) ? $iac+=1 : $iac; + } + $is_ajax_call = ($iac > 0) ? true : false; if ($is_ajax_call && $config['mc_antidos']['protect_ajax']) { + // we set this to navbar on purpose - if they screw with the REQUEST by adding more + // params it still gets added under navbar so multiple requests will still get capped $per_page = 'navbar'; } else if ($is_ajax_call && !$config['mc_antidos']['protect_ajax']) { // protect isn't on, we'll ignore it From 493c43e0ed49c1d4c1592b7c395fc5f8f0d8054b Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 26 Jan 2014 09:00:49 -0500 Subject: [PATCH 07/30] updated check in autoloader so default needs to be changed if SECHASH_CHECK is enabled --- public/include/autoloader.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 70871ac6..8fee8e48 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -1,5 +1,5 @@ Set a new SECURITY value to continue") : 0; +(SECURITY == "*)WT#&YHfd" && SECHASH_CHECK) ? die("public/index.php -> Set a new SECURITY value to continue") : 0; $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // SHA/Scrypt check From 795e019d0de3731fab71c98ab0487e84d6f7e952 Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 26 Jan 2014 09:25:46 -0500 Subject: [PATCH 08/30] cleaned up config options a bit --- public/include/config/global.inc.dist.php | 13 ++++++++++--- public/index.php | 4 +++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index d59d3ca5..63bee3a6 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -3,15 +3,22 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; /** * Forces extra security options when enabled + * + * You must have Memcache enabled and configured & Memcache anti-dos configured to use this. + * + * Check -> Memcache configuration + * Check -> Memcache anti resource-dos + * + * Runs a FILTER_VALIDATE_*TYPE on every parameter of bind_param + * Verifies server vs. bound protocol/host/port set below + * Enables memcache rate limiting of requests + * Verifies client when creating/resuming from a session */ $config['strict'] = true; $config['strict__enforce_ssl'] = false; $config['strict__bind_protocol'] = 'http'; $config['strict__bind_host'] = 'localhost'; $config['strict__bind_port'] = 80; -// CHANGE THIS KEY -define('strict__FIP_key', '45934debe4965c10c424254a2c8170df'); -// If you use this, you'll also have to change a key in public/index.php ... you'll see. /** * Do not edit this unless you have confirmed that your config has been updated! diff --git a/public/index.php b/public/index.php index f602a732..b06c87b5 100644 --- a/public/index.php +++ b/public/index.php @@ -19,9 +19,11 @@ limitations under the License. // Set a decently long SECURITY key with special chars etc define('SECURITY', '*)WT#&YHfd'); -// Disable the sechash check if you're sure, still checks if SECURITY defined as before +// Whether or not to check SECHASH for validity, still checks if SECURITY defined as before if disabled define('SECHASH_CHECK', true); +// Nothing below here to configure, move along... + // change SECHASH every second, we allow up to 3 sec back for slow servers if (SECHASH_CHECK) { function fip($tr=0) { return md5(SECURITY.(time()-$tr).SECURITY); } From 63c3b96a2940a350abd58491a72629b37059479f Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 26 Jan 2014 11:18:31 -0500 Subject: [PATCH 09/30] now enforce client & server validity on login with strict on fixed csrf token check for a few pages where it mightve been broken session manager now can be bound to base user class and used, like in login logout now pushes you to login regardless, no longer has param to push to custom url fixed validate client, hijacking sessions no longer works --- public/include/classes/base.class.php | 3 +++ public/include/classes/memcache_ad.class.php | 8 ++----- public/include/classes/strict.class.php | 24 +++++++++----------- public/include/classes/user.class.php | 24 ++++++++++++++------ public/include/pages/account/workers.inc.php | 2 +- public/include/pages/logout.inc.php | 8 ++----- public/index.php | 21 ++++++++++++----- 7 files changed, 51 insertions(+), 39 deletions(-) diff --git a/public/include/classes/base.class.php b/public/include/classes/base.class.php index 489ba7ff..385474f2 100644 --- a/public/include/classes/base.class.php +++ b/public/include/classes/base.class.php @@ -37,6 +37,9 @@ class Base { public function setUser($user) { $this->user = $user; } + public function setSessionManager($session) { + $this->session = $session; + } public function setConfig($config) { $this->config = $config; } diff --git a/public/include/classes/memcache_ad.class.php b/public/include/classes/memcache_ad.class.php index 72b48c1e..57ef2ca7 100644 --- a/public/include/classes/memcache_ad.class.php +++ b/public/include/classes/memcache_ad.class.php @@ -12,12 +12,8 @@ class MemcacheAntiDos 'hits_since_flush' => 0 ); public $rate_limit_this_request = false; - public function __construct($config, $userORip, $request, $mcSettings) { - if (PHP_OS == 'WINNT') { - require_once('memcached.class.php'); - } - $this->cache = new Memcached(); - $this->cache->addServer($mcSettings['host'], $mcSettings['port']); + public function __construct($config, &$memcache, $userORip, $request, $mcSettings) { + $this->cache = $memcache; // set our config options $per_page = $config['per_page']; $flush_sec = $config['flush_seconds']; diff --git a/public/include/classes/strict.class.php b/public/include/classes/strict.class.php index 558a5974..db23cd13 100644 --- a/public/include/classes/strict.class.php +++ b/public/include/classes/strict.class.php @@ -34,12 +34,8 @@ class SessionManager { public function verify_client($ip) { if ($this->started && $this->memcache_handle !== null && $this->verify_server()) { $read_client = $this->memcache_handle->get(md5((string)$ip)); - if ($read_client !== false) { - if (md5((string)$ip) !== $read_client[0]) { - return false; - } else { - return true; - } + if (is_array($read_client) && $read_client[0] == session_id()) { + return true; } else { return false; } @@ -54,7 +50,7 @@ class SessionManager { } } - public function set_cookie() { + public function set_cookie($ip) { if ($this->started && $this->memcache_handle !== null && $this->verify_server() && $this->verify_client($ip)) { @setcookie(session_name(), session_id(), $this->config_dura, $this->config_path, $this->config_domain, $this->config_secure, $this->config_httponly); } @@ -83,18 +79,19 @@ class SessionManager { $this->update_client($ip); $this->started = true; $this->current_session_id = session_id(); - $this->set_cookie(); + $this->set_cookie($ip); return true; } else { - if ($this->verify_server() && $this->verify_client($ip)) { - $this->update_client($ip); - return true; - } + $this->update_client($ip); + $this->started = true; + $this->current_session_id = session_id(); + $this->set_cookie($ip); + return true; } } } - public function __construct($config, $server_host) { + public function __construct($config, &$memcache, $server_host) { $this->config_dura = $config['cookie']['duration']; $this->config_path = $config['cookie']['path']; $this->config_domain = $config['cookie']['domain']; @@ -103,6 +100,7 @@ class SessionManager { if ($config['strict__enforce_ssl']) $config['strict__bind_protocol'] = 'https'; $this->bind_address = $config['strict__bind_protocol']."://".$config['strict__bind_host'].":".$config['strict__bind_port']; $this->server_http_host = $config['strict__bind_protocol']."://".$_SERVER['HTTP_HOST'].":".$config['strict__bind_port']; + $this->memcache_handle = $memcache; unset($config); $this->set_cookie_params((time()+$this->config_dura), $this->config_path, $this->config_domain, $this->config_secure, $this->config_httponly); } diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 9475a547..d7385b8a 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -493,10 +493,20 @@ class User extends Base { private function createSession($username) { $this->debug->append("STA " . __METHOD__, 4); $this->debug->append("Log in user to _SESSION", 2); - session_regenerate_id(true); - $_SESSION['AUTHENTICATED'] = '1'; - // $this->user from checkUserPassword - $_SESSION['USERDATA'] = $this->user; + if ($this->config['strict']) { + if ($this->session->verify_server()) { + if ($this->session->create_session($_SERVER['REMOTE_ADDR'])) { + $this->session->update_client($_SERVER['REMOTE_ADDR']); + $_SESSION['AUTHENTICATED'] = '1'; + $_SESSION['USERDATA'] = $this->user; + } + } + } else { + session_regenerate_id(true); + $_SESSION['AUTHENTICATED'] = '1'; + // $this->user from checkUserPassword + $_SESSION['USERDATA'] = $this->user; + } } /** @@ -514,7 +524,7 @@ class User extends Base { * @param none * @return true **/ - public function logoutUser($from="") { + public function logoutUser() { $this->debug->append("STA " . __METHOD__, 4); // Unset all of the session variables $_SESSION = array(); @@ -529,8 +539,8 @@ class User extends Base { session_regenerate_id(true); // Enforce a page reload and point towards login with referrer included, if supplied $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); - $location = @$_SERVER['HTTPS'] ? 'https://' . $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME'] : 'http://' . $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; - if (!empty($from)) $location .= '?page=login&to=' . urlencode($from); + $pushto = $_SERVER['SCRIPT_NAME'].'?page=login'; + $location = @$_SERVER['HTTPS'] ? 'https://' . $_SERVER['SERVER_NAME'] . $port . $pushto : 'http://' . $_SERVER['SERVER_NAME'] . $port . $pushto; // if (!headers_sent()) header('Location: ' . $location); exit(''); } diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php index 346a3de4..7403e0fa 100644 --- a/public/include/pages/account/workers.inc.php +++ b/public/include/pages/account/workers.inc.php @@ -4,7 +4,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($user->isAuthenticated()) { switch (@$_REQUEST['do']) { case 'delete': - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + if (!$config['csrf']['enabled'] || ($config['csrf']['enabled'])) { if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) { $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed', 'TYPE' => 'success'); } else { diff --git a/public/include/pages/logout.inc.php b/public/include/pages/logout.inc.php index 457c7b50..9b6e12a6 100644 --- a/public/include/pages/logout.inc.php +++ b/public/include/pages/logout.inc.php @@ -1,11 +1,7 @@ destroy_session($_SERVER['REMOTE_ADDR']); - $user->logoutUser(); -} else { - $user->logoutUser(); -} +$user->logoutUser(); + $smarty->assign("CONTENT", "default.tpl"); ?> diff --git a/public/index.php b/public/index.php index b06c87b5..c85ec279 100644 --- a/public/index.php +++ b/public/index.php @@ -50,8 +50,19 @@ $master_template = 'master.tpl'; // We include all needed files here, even though our templates could load them themself require_once(INCLUDE_DIR . '/autoloader.inc.php'); +if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $config['strict'])) { + if (PHP_OS == 'WINNT') { + require_once('memcached.class.php'); + } + // strict mode and memcache antidos need a memcache handle + $memcache = new Memcached(); + $memcache->addServer($config['memcache']['host'], $config['memcache']['port']); +} + if ($config['strict']) { - $session = new SessionManager($config, $_SERVER['HTTP_HOST']); + require_once(CLASS_DIR . '/memcache_ad.class.php'); + $session = new SessionManager($config, $memcache, $_SERVER['HTTP_HOST']); + $user->setSessionManager($session); if ($session->verify_server()) { $session->create_session($_SERVER['REMOTE_ADDR']); if ($session->verify_client($_SERVER['REMOTE_ADDR'])) { @@ -70,8 +81,6 @@ if ($config['strict']) { } // Rate limiting if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $config['strict']) { - require_once(CLASS_DIR . '/memcache_ad.class.php'); - $skip_check = false; $per_page = ($config['mc_antidos']['per_page']) ? $_SERVER['QUERY_STRING'] : ''; // if this is an api call we need to be careful not to time them out for those calls separately @@ -97,8 +106,8 @@ if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $confi $skip_check = true; } if (!$skip_check) { - $session->memcache_handle = new MemcacheAntiDos($config['mc_antidos'], $_SERVER['REMOTE_ADDR'], $per_page, $config['memcache']); - $rate_limit_reached = $session->memcache_handle->rateLimitRequest(); + $mcad = new MemcacheAntiDos($config['mc_antidos'], $memcache, $_SERVER['REMOTE_ADDR'], $per_page, $config['memcache']); + $rate_limit_reached = $mcad->rateLimitRequest(); $error_page = $config['mc_antidos']['error_push_page']; if ($rate_limit_reached == true) { if (!is_array($error_page) || count($error_page) < 1 || (empty($error_page['page']) && empty($error_page['action']))) { @@ -146,7 +155,7 @@ $action = (isset($_REQUEST['action']) && !is_array($_REQUEST['action'])) && isse // Check csrf token validity if necessary if ($config['csrf']['enabled'] && isset($_POST['ctoken']) && !empty($_POST['ctoken']) && !is_array($_POST['ctoken'])) { $csrftoken->valid = ($csrftoken->checkBasic($user->getCurrentIP(), $arrPages[$page], $_POST['ctoken'])) ? 1 : 0; -} else if ($config['csrf']['enabled'] && (!@$_POST['ctoken'] || empty($_POST['ctoken']) || is_array($_POST['ctoken']))) { +} else if ($config['csrf']['enabled'] && (!@$_POST['ctoken'] || empty($_POST['ctoken']))) { $csrftoken->valid = 0; } if ($config['csrf']['enabled']) $smarty->assign('CTOKEN', $csrftoken->getBasic($user->getCurrentIP(), $arrPages[$page])); From c373fc7192337ce290f9265d638d995005913e68 Mon Sep 17 00:00:00 2001 From: xisi Date: Sun, 26 Jan 2014 11:42:14 -0500 Subject: [PATCH 10/30] removed exploits/added to gitignore for later --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 15e9bfc9..3f61187e 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ # Test configs public/include/config/global.inc.scrypt.php public/include/config/global.inc.sha.php +exploits/* # IDE Settings /.idea/* From 6398e5dfec72af263c2ef4dccfbd97b16130669e Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 28 Jan 2014 06:12:00 -0500 Subject: [PATCH 11/30] merged session manager/memcache limiter cleanup for PR --- .gitignore | 2 +- cronjobs/shared.inc.php | 15 ++ public/include/admin_checks.php | 113 +++++++++ public/include/autoloader.inc.php | 4 + public/include/classes/memcache_ad.class.php | 125 +++++++--- public/include/classes/strict.class.php | 234 +++++++++++-------- public/include/classes/user.class.php | 16 +- public/include/config/global.inc.dist.php | 82 +------ public/include/config/security.inc.dist.php | 136 +++++++++++ public/include/database.inc.php | 2 +- public/include/pages/login.inc.php | 20 +- public/include/pages/logout.inc.php | 13 +- public/include/version.inc.php | 2 +- public/index.php | 52 +++-- public/templates/mpos/login/default.tpl | 1 - 15 files changed, 566 insertions(+), 251 deletions(-) create mode 100644 public/include/admin_checks.php create mode 100644 public/include/config/security.inc.dist.php diff --git a/.gitignore b/.gitignore index 3f61187e..03ef8272 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Local Config /public/include/config/global.inc.php +/public/include/config/security.inc.php # Templates /public/templates/compile/*.php @@ -14,7 +15,6 @@ # Test configs public/include/config/global.inc.scrypt.php public/include/config/global.inc.sha.php -exploits/* # IDE Settings /.idea/* diff --git a/cronjobs/shared.inc.php b/cronjobs/shared.inc.php index ecc3da11..fc0d4c9a 100644 --- a/cronjobs/shared.inc.php +++ b/cronjobs/shared.inc.php @@ -18,6 +18,21 @@ limitations under the License. */ +define('SECURITY', '*)WT#&YHfd'); +// Whether or not to check SECHASH for validity, still checks if SECURITY defined as before if disabled +define('SECHASH_CHECK', false); + +// Nothing below here to configure, move along... + +// change SECHASH every second, we allow up to 3 sec back for slow servers +if (SECHASH_CHECK) { + function fip($tr=0) { return md5(SECURITY.(time()-$tr).SECURITY); } + define('SECHASH', fip()); + function cfip() { return (fip()==SECHASH||fip(1)==SECHASH||fip(2)==SECHASH) ? 1 : 0; } +} else { + function cfip() { return (@defined('SECURITY')) ? 1 : 0; } +} + // MODIFY THIS // We need to find our include files so set this properly define("BASEPATH", "../public/"); diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php new file mode 100644 index 00000000..1a28da32 --- /dev/null +++ b/public/include/admin_checks.php @@ -0,0 +1,113 @@ +isAdmin(@$_SESSION['USERDATA']['id'])) { + + if (!include_once(INCLUDE_DIR . '/lib/jsonRPCClient.php')) die('Unable to load libs'); + + $notice = array(); + $enotice = array(); + $error = array(); + + // setup some basic stuff for checking + $apache_user = posix_getuid(); + $apache_user = (function_exists('posix_getpwuid')) ? posix_getpwuid($apache_user) : $apache_user; + + // setup checks + // check if memcache isn't available but enabled in config -> error + if (!class_exists('Memcached') && $config['memcache']['enabled']) { + $error[] = "You have memcache enabled in your config and it's not available. Install the package on your system."; + } + // if it's not enabled, test it if it exists, if it works -> error tell them to enable, -> otherwise notice it's disabled + if (!$config['memcache']['enabled']) { + if (PHP_OS == 'WINNT') { + require_once(CLASS_DIR . 'memcached.class.php'); + } + if (class_exists('Memcached')) { + $memcache_test = @new Memcached(); + $memcache_test_add = @$memcache_test->addServer($config['memcache']['host'], $config['memcache']['port']); + $randmctv = rand(5,10); + $memcache_test_set = @$memcache_test->set('test_mpos_setval', $randmctv); + $memcache_test_get = @$memcache_test->get('test_mpos_setval'); + } + if (class_exists('Memcached') && $memcache_test_get == $randmctv) { + $error[] = "You have memcache disabled in the config and it's available & works! Enable it."; + } else { + $notice[] = "Memcache is disabled; Almost every linux distro has packages for it, you should be using it if you can."; + } + } + // check if we can write templates/cache and templates/compile -> error + if (!is_writable(THEME_DIR.'/cache')) { + $error[] = "templates/cache folder is not writable for uid {$apache_user['name']}"; + } + if (!is_writable(THEME_DIR.'/compile')) { + $error[] = "templates/compile folder is not writable for uid {$apache_user['name']}"; + } + // check if daemon can connect -> error + try { + if ($bitcoin->can_connect() !== true) { + $error[] = "Unable to connect to coin daemon using provided credentials"; + } + } catch (Exception $e) { + } + // if coldwallet is not empty, check if the address is valid -> error + if (!empty($config['coldwallet']['address'])) { + try { + if ($bitcoin->can_connect() == true) { + $validate_cold_address = $bitcoin->validateaddress($config['coldwallet']['address']); + if (!$validate_cold_address['isvalid']) { + $error[] = "Your cold wallet address is SET and INVALID"; + } + } + } catch (Exception $e) { + } + } + // if database connection fails -> error + $db_connect = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); + if (mysqli_connect_errno() || !array_key_exists('client_info', $db_connect)) { + $error[] = "Unable to connect to mysql using provided credentials"; + } + if (($config['strict'] || $config['mc_antidos']) && !$config['memcache']['enabled']) { + $error[] = "strict or mc_antidos are enabled and memcache is not, memcache is required to use these."; + } + // poke stratum using gettingstarted details -> enotice + $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($socket !== false) { + $address = @gethostbyname($config['gettingstarted']['stratumurl']); + $result = @socket_connect($socket, $address, $config['gettingstarted']['stratumport']); + if ($result !== 1) { + $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; + } + $close = @socket_close($socket); + } + // security checks + // strict not on -> notice + if (!$config['strict']) { + $notice[] = "strict is disabled - if you have memcache, you should turn this on."; + } + // salts too short -> notice, salts default -> error + if ((strlen(SALT) < 24) || (strlen(SALTY) < 24) || SALT == 'PLEASEMAKEMESOMETHINGRANDOM' || SALTY == 'THISSHOULDALSOBERRAANNDDOOM') { + if (SALT == 'PLEASEMAKEMESOMETHINGRANDOM' || SALTY == 'THISSHOULDALSOBERRAANNDDOOM') { + $error[] = "You absolutely SHOULD NOT leave your SALT or SALTY default"; + } else { + $notice[] = "SALT or SALTY is too short, they should be more than 24 characters and changing them will require registering again."; + } + } + + // display the errors + foreach ($enotice as $en) { + $_SESSION['POPUP'][] = array('CONTENT' => $en, 'TYPE' => 'info'); + } + if (!count($notice) && !count($error)) { + $_SESSION['POPUP'][] = array('CONTENT' => 'The config options we checked seem OK', 'TYPE' => 'success'); + } else { + foreach ($notice as $n) { + $_SESSION['POPUP'][] = array('CONTENT' => $n, 'TYPE' => 'warning'); + } + foreach ($error as $e) { + $_SESSION['POPUP'][] = array('CONTENT' => $e, 'TYPE' => 'errormsg'); + } + } +} + +?> \ No newline at end of file diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 8fee8e48..5042e09e 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -71,4 +71,8 @@ require_once(INCLUDE_DIR . '/lib/scrypt.php'); // Include our versions require_once(INCLUDE_DIR . '/version.inc.php'); +if ($user->isAdmin(@$_SESSION['USERDATA']['id'])) { + //include_once(INCLUDE_DIR . '/admin_checks.inc.php'); +} + ?> diff --git a/public/include/classes/memcache_ad.class.php b/public/include/classes/memcache_ad.class.php index 57ef2ca7..25b48cf5 100644 --- a/public/include/classes/memcache_ad.class.php +++ b/public/include/classes/memcache_ad.class.php @@ -4,66 +4,119 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; class MemcacheAntiDos { public $cache; - public static $key = 'mcad_'; - public static $request_model = array( - 'ident' => '', - 'last_hit' => 0, - 'last_flush' => 0, - 'hits_since_flush' => 0 - ); public $rate_limit_this_request = false; - public function __construct($config, &$memcache, $userORip, $request, $mcSettings) { + public $rate_limit_api_request = false; + public $rate_limit_site_request = false; + public function __construct($config, &$memcache, $userORip, $request='', $mcSettings) { $this->cache = $memcache; // set our config options - $per_page = $config['per_page']; - $flush_sec = $config['flush_seconds']; - $rate_limit = $config['rate_limit']; + $per_page = ''; + $flush_sec_api = $config['flush_seconds_api']; + $rate_limit_api = $config['rate_limit_api']; + $flush_sec_site = $config['flush_seconds_site']; + $rate_limit_site = $config['rate_limit_site']; + $ajax_add = $config['ajax_hits_additive']; unset($config); // prep stuff we need to check this request - $key_md5 = substr(md5($userORip), 0, 4); - $request_md5 = substr(md5($request), 0, 4); - $request_key = $mcSettings['keyprefix'].self::$key.$key_md5."_".$request_md5."_".$per_page; - $request_data = $this->cache->get($request_key); + $key_md5 = md5($mcSettings['keyprefix'].$userORip); + $request_data = $this->cache->get($key_md5); $now = time(); + $max_req_flush = max(array($flush_sec_api,$flush_sec_site)); // check the request if (is_array($request_data)) { // this request key already exists, update it - $request_data['ident'] = $key_md5; - $request_data['last_hit'] = $now; - $request_data['hits_since_flush'] += 1; + $request_data['la'] = $now; + if ($request == 'api') { + $request_data['ha'] += 1; + if ($ajax_add) { + $request_data['hn'] += 1; + } + } else { + $request_data['hn'] += 1; + } // not rate limited yet, update the rest of the object - if ($request_data['hits_since_flush'] < $rate_limit) { - if (($request_data['last_flush'] + $flush_sec) <= $now || ($request_data['last_hit'] + $flush_sec) <= $now) { - // needs to be flushed - $request_data['hits_since_flush'] = 0; - $request_data['last_hit'] = 0; - $request_data['last_flush'] = $now; - // update the object - $this->cache->set($request_key, $request_data, $flush_sec); - $this->rate_limit_this_request = false; + if (($request_data['hn'] < $rate_limit_site) && ($request_data['ha'] < $rate_limit_api)) { + + if (((($request_data['hnl'] + $flush_sec_site) <= $now) || ($request_data['hal'] + $flush_sec_api) <= $now) || (($request_data['la'] + $max_req_flush) <= $now)) { + // needs to be flushed & updated + $new = $this->getRequestBase(); + $new['key'] = $key_md5; + $new['sid'] = session_id(); + $new['ua'] = md5($_SERVER['HTTP_USER_AGENT']); + $new['ip'] = $key_md5; + $new['la'] = $now; + $new['hal'] = ((($request_data['hal'] + $flush_sec_api) <= $now)) ? $now : 1; + $new['hnl'] = ((($request_data['hnl'] + $flush_sec_site) <= $now)) ? $now : 1; + $this->cache->set($key_md5, $new, $max_req_flush); + $this->rate_limit_api_request = ($request_data['ha'] >= $rate_limit_api) ? true : false; + $this->rate_limit_site_request = ($request_data['hn'] >= $rate_limit_site) ? true : false; + //$this->rate_limit_this_request = false; } else { // no flush, just update - $this->cache->set($request_key, $request_data, $flush_sec); - $this->rate_limit_this_request = false; + $new = $this->getRequestBase(); + $new['key'] = $key_md5; + $new['sid'] = session_id(); + $new['ua'] = md5($_SERVER['HTTP_USER_AGENT']); + $new['ip'] = $key_md5; + $new['la'] = time(); + $new['ha'] = $request_data['ha']; + $new['hal'] = $request_data['hal']; + $new['hn'] = $request_data['hn']; + $new['hnl'] = $request_data['hnl']; + $this->cache->set($key_md5, $new, $max_req_flush); + //$this->rate_limit_this_request = false; + $this->rate_limit_api_request = ($request_data['ha'] >= $rate_limit_api) ? true : false; + $this->rate_limit_site_request = ($request_data['hn'] >= $rate_limit_site) ? true : false; } } else { // too many hits, we should rate limit this - $this->rate_limit_this_request = true; + //$this->rate_limit_this_request = true; + $this->rate_limit_api_request = ($request_data['ha'] >= $rate_limit_api) ? true : false; + $this->rate_limit_site_request = ($request_data['hn'] >= $rate_limit_site) ? true : false; } } else { // doesn't exist for this request_key, create one - $new_data = self::$request_model; - $new_data['ident'] = $key_md5; - $new_data['last_hit'] = time(); - $new_data['hits_since_flush'] = 1; - $new_data['last_flush'] = $now; - $this->cache->set($request_key, $new_data, $flush_sec); + $new = $this->getRequestBase(); + $new['key'] = $key_md5; + $new['sid'] = session_id(); + $new['ua'] = md5($_SERVER['HTTP_USER_AGENT']); + $new['ip'] = $key_md5; + $new['la'] = time(); + if ($request == 'api') { + $new['ha'] += 1; + if ($ajax_add) { + $new['hn'] += 1; + } + } else { + $new['hn'] += 1; + } + $this->cache->set($key_md5, $new, $max_req_flush); $this->rate_limit_this_request = false; } } + public function getRequestBase() { + $new = array( + 'key' => '', + 'sid' => '', + 'ua' => '', + 'ip' => '', + 'la' => 0, + 'hn' => 0, + 'hnl' => 0, + 'ha' => 0, + 'hal' => 0 + ); + return $new; + } public function rateLimitRequest() { return $this->rate_limit_this_request; } + public function rateLimitSite() { + return $this->rate_limit_site_request; + } + public function rateLimitAPI() { + return $this->rate_limit_api_request; + } } ?> \ No newline at end of file diff --git a/public/include/classes/strict.class.php b/public/include/classes/strict.class.php index db23cd13..9a535c54 100644 --- a/public/include/classes/strict.class.php +++ b/public/include/classes/strict.class.php @@ -1,108 +1,140 @@ bind_address !== $this->server_http_host) { - return false; - } else { - return true; - } + public function session_delete_key($key) { + $read = $this->memcache->delete($key); } - - public function verify_client($ip) { - if ($this->started && $this->memcache_handle !== null && $this->verify_server()) { - $read_client = $this->memcache_handle->get(md5((string)$ip)); - if (is_array($read_client) && $read_client[0] == session_id()) { - return true; - } else { - return false; + private $validation_misses = 0; + private $initial_ua; + public function create_or_update_client($client, $force=false, $login=false) { + $read = $this->memcache->get($client['key']); + // this needs to be available later + $update = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); + $update['sid'] = $client['sid']; + $update['ua'] = md5($this->initial_ua); + $update['ip'] = $client['ip']; + $update['la'] = time(); + $update['key'] = md5($this->memcache_key.$client['ip']); + $validation_misses = 0; + if ($read !== false) { + $read_model = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); + $read_model['sid'] = @$read['sid']; + $read_model['ip'] = @$read['ip']; + $read_model['ua'] = @$read['ua']; + $read_model['la'] = @$read['la']; + $read_model['key'] = md5($this->memcache_key.$read['ip']); + // key already exists, update + if ($this->validate_client) { + if ($this->verify_client($read_model, $update, $login)) { + $update_client = $this->memcache->set($update['key'], $update); + } } } else { - return false; - } - } - - public function update_client($ip) { - if ($this->started && $this->memcache_handle !== null && $this->verify_client($ip)) { - $this->memcache_handle->set(md5((string)$ip), array($this->current_session_id, time())); - } - } - - public function set_cookie($ip) { - if ($this->started && $this->memcache_handle !== null && $this->verify_server() && $this->verify_client($ip)) { - @setcookie(session_name(), session_id(), $this->config_dura, $this->config_path, $this->config_domain, $this->config_secure, $this->config_httponly); - } - } - - public function destroy_session($ip) { - if ($this->started && $this->verify_server() && $this->verify_client($ip)) { - $this->memcache_handle->delete(md5((string)$ip)); - if (ini_get('session.use_cookies')) { - setcookie(session_name(), '', time() - 42000, $config_path, $config_domain, $config_secure, $config_httponly); - } - session_destroy(); - session_regenerate_id(true); - } - } - - public function create_session($ip) { - if (!$this->verify_server()) { - return false; - } else { - $session_start = @session_start(); - if (!$session_start) { - session_destroy(); - session_regenerate_id(true); - session_start(); - $this->update_client($ip); - $this->started = true; - $this->current_session_id = session_id(); - $this->set_cookie($ip); - return true; - } else { - $this->update_client($ip); - $this->started = true; - $this->current_session_id = session_id(); - $this->set_cookie($ip); - return true; + $update_client = $this->memcache->set($client['key'], $client); + if ($force && $login) { + $update_client = $this->memcache->set($update['key'], $update); } } } - - public function __construct($config, &$memcache, $server_host) { - $this->config_dura = $config['cookie']['duration']; - $this->config_path = $config['cookie']['path']; - $this->config_domain = $config['cookie']['domain']; - $this->config_secure = $config['cookie']['secure']; - $this->config_httponly = $config['cookie']['httponly']; - if ($config['strict__enforce_ssl']) $config['strict__bind_protocol'] = 'https'; - $this->bind_address = $config['strict__bind_protocol']."://".$config['strict__bind_host'].":".$config['strict__bind_port']; - $this->server_http_host = $config['strict__bind_protocol']."://".$_SERVER['HTTP_HOST'].":".$config['strict__bind_port']; - $this->memcache_handle = $memcache; - unset($config); - $this->set_cookie_params((time()+$this->config_dura), $this->config_path, $this->config_domain, $this->config_secure, $this->config_httponly); + public function verify_client($client_model, $data, $login=false) { + $fails = 0; + $fails += ((count($client_model)) !== (count($data))) ? 1 : 0; + $fails += ($client_model['ua'] !== $data['ua']) ? 1 : 0; + $fails += ($client_model['ip'] !== $data['ip']) ? 1 : 0; + $now = time(); + $this->validation_misses = $fails; + if ($fails > $this->validate_client_num && $login == false) { + // something changed + $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); + $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; + $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; + $this->session_delete_key($client_model['key']); + $this->session_delete_key($data['key']); + @session_start(); + @session_regenerate_id(true); + $_SESSION = null; + $_SESSION['POPUP'][] = array('CONTENT' => "Session revoked due to a change in your client. You may have a plugin messing with your useragent, or your IP address may have changed.", 'TYPE' => 'warning'); + $location.= '?page=login'; + if (!headers_sent()) exit(header('Location: ' . $location)); + exit(''); + } + return ($fails > 0) ? false : true; + } + public function read_if_client_exists($client_key) { + if ($this->memcache !== null) { + $exists = $this->memcache->get($client_key); + } + return ($exists !== null) ? $exists : false; + } + public function regen_session_id() { + $sidbefore = @session_id(); + @session_regenerate_id(true); + $sid = session_id(); + return $sid; + } + public function __construct($config, &$memcache) { + $this->initial_ua = $_SERVER['HTTP_USER_AGENT']; + $this->memcache = $memcache; + $this->memcache_key = $config['memcache']['keyprefix']; + if ($config['strict__verify_client']) { + $this->validate_client = true; + $this->validate_client_ip = $config['strict__verify_client_ip']; + $this->validate_client_ua = $config['strict__verify_client_useragent']; + $this->validate_client_sid = $config['strict__verify_client_sessionid']; + $this->validate_client_num = 0; + if ($config['strict__verify_server']) { + $proto = (@$_SERVER['HTTPS'] == "on") ? 'https' : 'http'; + $location = $proto."://".$_SERVER['SERVER_NAME'] . $_SERVER['SERVER_PORT']; + if ($config['strict__verify_server']) { + if ($config['strict__bind_protocol']."://".$config['strict__bind_host'].$config['strict__bind_port'] !== $location) { + return false; + } + } + } + $client = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); + $client['ua'] = md5($_SERVER['HTTP_USER_AGENT']); + $client['ip'] = md5($_SERVER['REMOTE_ADDR']); + $client['la'] = time(); + $client['key'] = md5($this->memcache_key.$client['ip']); + $read = $this->read_if_client_exists($client['key']); + } + session_set_cookie_params((time()+$config['cookie']['duration']), $config['cookie']['path'], $config['cookie']['domain'], false, true); + $session_start = @session_start(); + $client['sid'] = session_id(); + $valid_session_id = $this->valid_session_id($client['sid']); + if (!$valid_session_id || !$session_start) { + @session_destroy(); + $client['sid'] = $this->regen_session_id(); + session_start(); + } + if ($read !== null) { + // client exists, verify + $this->create_or_update_client($client, true, false); + + } else { + // doesn't exist + $this->create_or_update_client($client, true, true); + } + @setcookie(session_name(), $client['sid'], (time()+$config['cookie']['duration']), $config['cookie']['path'], $config['cookie']['domain'], false, true); + // post changes validate + if ($this->validate_client) { + $read_post = $this->read_if_client_exists($client['key']); + if ($read_post !== null) { + $this->verify_client($client, $read_post, true); + } + } } } @@ -115,26 +147,28 @@ class mysqli_strict extends mysqli { $acopy = $args; $nargs = count($args); for($i=1;$i<$nargs;$i++) { - $pos = substr($paramTypes, ($i-1), 1); + $ipos = ($i-1); + $pos = substr($paramTypes, $ipos, 1); switch ($pos) { case 's': $return_str = filter_var($acopy[$i], FILTER_VALIDATE_STRING, FILTER_NULL_ON_FAILURE); - return ($return_str !== null) ? (string)$return_str : false; + $acopy[$i] = ($return_str !== null) ? (string)$return_str : null; break; case 'i': $return_int = filter_var($acopy[$i], FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE); - return ($return_int !== null) ? (int)$return_int : false; + $acopy[$i] = ($return_int !== null) ? (int)$return_int : null; break; case 'd': $return_dbl = filter_var($acopy[$i], FILTER_VALIDATE_FLOAT, FILTER_NULL_ON_FAILURE); - return ($return_dbl !== null) ? (float)$return_dbl : false; + $acopy[$i] = ($return_dbl !== null) ? (float)$return_dbl : null; break; case 'b': $return_bool = filter_var($acopy[$i], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); - return ($return_bool !== null) ? (bool)$return_bool : false; + $acopy[$i] = ($return_bool !== null) ? (bool)$return_bool : null; break; } } + return (in_array(null, $acopy)); } } } diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index d7385b8a..1c0feee0 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -494,13 +494,10 @@ class User extends Base { $this->debug->append("STA " . __METHOD__, 4); $this->debug->append("Log in user to _SESSION", 2); if ($this->config['strict']) { - if ($this->session->verify_server()) { - if ($this->session->create_session($_SERVER['REMOTE_ADDR'])) { - $this->session->update_client($_SERVER['REMOTE_ADDR']); - $_SESSION['AUTHENTICATED'] = '1'; - $_SESSION['USERDATA'] = $this->user; - } - } + session_regenerate_id(true); + $_SESSION['AUTHENTICATED'] = '1'; + // $this->user from checkUserPassword + $_SESSION['USERDATA'] = $this->user; } else { session_regenerate_id(true); $_SESSION['AUTHENTICATED'] = '1'; @@ -537,10 +534,11 @@ class User extends Base { session_destroy(); // Enforce generation of a new Session ID and delete the old session_regenerate_id(true); + // Enforce a page reload and point towards login with referrer included, if supplied $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); $pushto = $_SERVER['SCRIPT_NAME'].'?page=login'; - $location = @$_SERVER['HTTPS'] ? 'https://' . $_SERVER['SERVER_NAME'] . $port . $pushto : 'http://' . $_SERVER['SERVER_NAME'] . $port . $pushto; + $location = (@$_SERVER['HTTPS'] == 'on') ? 'https://' . $_SERVER['SERVER_NAME'] . $port . $pushto : 'http://' . $_SERVER['SERVER_NAME'] . $port . $pushto; // if (!headers_sent()) header('Location: ' . $location); exit(''); } @@ -804,7 +802,7 @@ class User extends Base { * @param none * @return bool **/ - public function isAuthenticated($logout=true) { +public function isAuthenticated($logout=true) { $this->debug->append("STA " . __METHOD__, 4); if (@$_SESSION['AUTHENTICATED'] == true && !$this->isLocked($_SESSION['USERDATA']['id']) && diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 63bee3a6..63c44b83 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -1,25 +1,6 @@ Memcache configuration - * Check -> Memcache anti resource-dos - * - * Runs a FILTER_VALIDATE_*TYPE on every parameter of bind_param - * Verifies server vs. bound protocol/host/port set below - * Enables memcache rate limiting of requests - * Verifies client when creating/resuming from a session - */ -$config['strict'] = true; -$config['strict__enforce_ssl'] = false; -$config['strict__bind_protocol'] = 'http'; -$config['strict__bind_host'] = 'localhost'; -$config['strict__bind_port'] = 80; - /** * Do not edit this unless you have confirmed that your config has been updated! * This is used in the version check to ensure you run the latest version of the configuration file. @@ -27,6 +8,11 @@ $config['strict__bind_port'] = 80; **/ $config['version'] = '0.0.7'; +/** + * Unless you disable this, we'll do a quick check on your config first. + */ +$config['skip_config_tests'] = false; + // Our include directory for additional features define('INCLUDE_DIR', BASEPATH . 'include'); @@ -119,64 +105,6 @@ $config['coldwallet']['address'] = ''; $config['coldwallet']['reserve'] = 50; $config['coldwallet']['threshold'] = 5; -/** - * E-mail confirmations for user actions - * - * Explanation: - * To increase security for users, account detail changes can require - * an e-mail confirmation prior to performing certain actions. - * - * Options: - * enabled : Whether or not to require e-mail confirmations - * details : Require confirmation to change account details - * withdraw : Require confirmation to manually withdraw/payout - * changepw : Require confirmation to change password - * - * Default: - * enabled = true - * details = true - * withdraw = true - * changepw = true - */ -$config['twofactor']['enabled'] = true; -$config['twofactor']['options']['details'] = true; -$config['twofactor']['options']['withdraw'] = true; -$config['twofactor']['options']['changepw'] = true; - -/** - * CSRF protection - * - * Explanation: - * To help protect against CSRF, we can generate a hash that changes every minute - * and is unique for each user/IP and page or use, and check against that when a - * form is submitted. - * - * Options: - * enabled = Whether or not we will generate & check for valid CSRF tokens - * Default: - * enabled = true - */ -$config['csrf']['enabled'] = true; - -/** - * Lock account after maximum failed logins - * - * Explanation: - * To avoid accounts being hacked by brute force attacks, - * set a maximum amount of failed login or pin entry attempts before locking - * the account. They will need to contact site support to re-enable the account. - * - * This also applies for invalid PIN entries, which is covered by the pin option. - * - * Workers are not affected by this lockout, mining will continue as usual. - * - * Default: - * login = 3 - * pin = 3 - **/ -$config['maxfailed']['login'] = 3; -$config['maxfailed']['pin'] = 3; - /** * Getting Started Config * diff --git a/public/include/config/security.inc.dist.php b/public/include/config/security.inc.dist.php new file mode 100644 index 00000000..66612efe --- /dev/null +++ b/public/include/config/security.inc.dist.php @@ -0,0 +1,136 @@ + Memcache configuration + * Check -> Memcache anti resource-dos + * + * Options Default Explanation + * ------- + ------- + ----------- + * strict : true : Whether or not to use strict mode + * __https_only : false : Requires/pushes to https + * __mysql_filter : true : Uses a mysqli shim to use php filters on all incoming data + * __verify_client : true : Verifies the client using specified settings + * __verify_client_ip : true : If the client request suddenly switches IP, trigger a failure + * __verify_client_useragent : true : If the client request suddenly switches Useragent, trigger a failure + * __verify_client_sessionid : true : If the client request suddenly switches SessionID, trigger a failure + * __verify_client_fails : 0 : Maximum number of client-side inconsistencies to accept before revoking sessions + * __verify_server : false : Verifies the server is valid for this request + * __bind_protocol : https : Server validate protocol; http or https + * __bind_host : '' : Server validate host; ie. your domain or subdomain + * __bind_port : 443 : Server validate port; 80 / 443 / something else + **/ +$config['strict'] = true; +$config['strict__https_only'] = false; +$config['strict__mysql_filter'] = true; +$config['strict__verify_client'] = true; +$config['strict__verify_client_ip'] = true; +$config['strict__verify_client_useragent'] = true; +$config['strict__verify_client_sessionid'] = true; +$config['strict__verify_client_fails'] = 0; +$config['strict__verify_server'] = false; +$config['strict__bind_protocol'] = 'https'; +$config['strict__bind_host'] = ''; +$config['strict__bind_port'] = 443; + +/** + * Memcache anti resource-dos protection / request rate limiting + * + * Explanation: + * Because bots/angry users can just fire away at pages or f5 us to death, we can attempt to rate limit requests + * using memcache - now shares data with session manager. + * + * Options: + * enabled = Whether or not we will try to rate limit requests + * protect_ajax = If enabled, we will also watch the ajax calls for rate limiting and kill bad requests + * ajax_hits_additive = If enabled, ajax hits will count towards the site counter as well as the ajax counter + * flush_seconds_api = Number of seconds between each flush of user/ajax counter + * rate_limit_api = Number of api requests allowed per flush_seconds_api + * flush_seconds_site = Number of seconds between each flush of user/site counter + * rate_limit_site = Number of site requests allowed per flush_seconds_site + * ignore_admins = Ignores the rate limit for admins + * error_push_page = Page/action array to push users to a specific page, look in the URL! + * Empty = 'You are sending too many requests too fast!' on a blank page + * Default: + * enabled = true + * protect_ajax = true + * ajax_hits_additive = false + * flush_seconds_api = 60 + * rate_limit_api = 20 + * flush_seconds_site = 60 + * rate_limit_site = 30 + * ignore_admins = true + * error_push_page = array('page' => 'error', 'action' => 'ratelimit'); + */ +$config['mc_antidos']['enabled'] = true; +$config['mc_antidos']['protect_ajax'] = true; +$config['mc_antidos']['ajax_hits_additive'] = false; +$config['mc_antidos']['flush_seconds_api'] = 60; +$config['mc_antidos']['rate_limit_api'] = 20; +$config['mc_antidos']['flush_seconds_site'] = 60; +$config['mc_antidos']['rate_limit_site'] = 30; +$config['mc_antidos']['ignore_admins'] = true; +$config['mc_antidos']['error_push_page'] = array('page' => 'error', 'action' => 'ratelimit'); + +/** + * CSRF protection config + * + * Explanation: + * To help protect against CSRF, we can generate a hash that changes every minute + * and is unique for each user/IP and page or use, and check against that when a + * form is submitted. + * + * Options: + * enabled = Whether or not we will generate/check for valid CSRF tokens + * Default: + * enabled = true + */ +$config['csrf']['enabled'] = true; + +/** + * E-mail confirmations for user actions + * + * Explanation: + * To increase security for users, account detail changes can require + * an e-mail confirmation prior to performing certain actions. + * + * Options: + * enabled : Whether or not to require e-mail confirmations + * details : Require confirmation to change account details + * withdraw : Require confirmation to manually withdraw/payout + * changepw : Require confirmation to change password + * + * Default: + * enabled = true + * details = true + * withdraw = true + * changepw = true + */ +$config['twofactor']['enabled'] = true; +$config['twofactor']['options']['details'] = true; +$config['twofactor']['options']['withdraw'] = true; +$config['twofactor']['options']['changepw'] = true; + +/** + * Lock account after maximum failed logins + * + * Explanation: + * To avoid accounts being hacked by brute force attacks, + * set a maximum amount of failed login or pin entry attempts before locking + * the account. They will need to contact site support to re-enable the account. + * + * This also applies for invalid PIN entries, which is covered by the pin option. + * + * Workers are not affected by this lockout, mining will continue as usual. + * + * Default: + * login = 3 + * pin = 3 + **/ +$config['maxfailed']['login'] = 3; +$config['maxfailed']['pin'] = 3; + +?> \ No newline at end of file diff --git a/public/include/database.inc.php b/public/include/database.inc.php index 870e6dfa..1146e239 100644 --- a/public/include/database.inc.php +++ b/public/include/database.inc.php @@ -2,7 +2,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // Instantiate class, we are using mysqlng -if ($config['strict']) { +if ($config['strict'] && $config['strict__mysql_filter']) { $mysqli = new mysqli_strict($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); } else { $mysqli = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); diff --git a/public/include/pages/login.inc.php b/public/include/pages/login.inc.php index ff3b36ae..84964672 100644 --- a/public/include/pages/login.inc.php +++ b/public/include/pages/login.inc.php @@ -24,10 +24,22 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail // Check if recaptcha is enabled, process form data if valid if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + // check if login is correct if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) { - $port = ($_SERVER["SERVER_PORT"] == "80" or $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); - $location = @$_SERVER['HTTPS'] ? 'https://' : 'http://'; - $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME'] . '?page=dashboard'; + $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); + $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; + $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; + if ($config['strict']) { + $update = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); + $session->regen_session_id(); + $update['sid'] = session_id(); + $update['ua'] = md5($_SERVER['HTTP_USER_AGENT']); + $update['ip'] = md5($_SERVER['REMOTE_ADDR']); + $update['la'] = time(); + $update['key'] = md5($update['ip']); + $session->create_or_update_client($update, true, true); + $location.= '?page=dashboard'; + } if (!headers_sent()) header('Location: ' . $location); exit(''); } else { @@ -40,7 +52,7 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'errormsg'); } } - // Load login template $smarty->assign('CONTENT', 'default.tpl'); + ?> diff --git a/public/include/pages/logout.inc.php b/public/include/pages/logout.inc.php index 9b6e12a6..c15f350a 100644 --- a/public/include/pages/logout.inc.php +++ b/public/include/pages/logout.inc.php @@ -1,7 +1,18 @@ logoutUser(); +if ($config['strict']) { + $user->logoutUser(); + $update = $session::$client_model; + $update['sid'] = session_id(); + $update['ua'] = $_SERVER['HTTP_USER_AGENT']; + $update['ip'] = $_SERVER['REMOTE_ADDR']; + $update['la'] = time(); + $update['key'] = md5($update['ua'].$update['ip']); + $session->create_or_update_client($update, true); +} else { + $user->logoutUser(); +} $smarty->assign("CONTENT", "default.tpl"); ?> diff --git a/public/include/version.inc.php b/public/include/version.inc.php index 6206c0a2..d1db6f62 100644 --- a/public/include/version.inc.php +++ b/public/include/version.inc.php @@ -1,7 +1,7 @@ addServer($config['memcache']['host'], $config['memcache']['port']); } -if ($config['strict']) { +if ($config['memcache']['enabled'] && $config['strict'] || $config['mc_antidos']['enabled']) { require_once(CLASS_DIR . '/memcache_ad.class.php'); - $session = new SessionManager($config, $memcache, $_SERVER['HTTP_HOST']); - $user->setSessionManager($session); - if ($session->verify_server()) { - $session->create_session($_SERVER['REMOTE_ADDR']); - if ($session->verify_client($_SERVER['REMOTE_ADDR'])) { - $session->update_client($_SERVER['REMOTE_ADDR']); - } +} + +if ($config['memcache']['enabled'] && $config['strict']) { + $session = new strict_session($config, $memcache); + if ($config['strict__verify_server'] && !$session) { + // server not verified, session manager will kill the client verification failures + exit(header('HTTP/1.1 401 Unauthorized')); } } else { - session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); $session_start = @session_start(); + session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); if (!$session_start) { session_destroy(); session_regenerate_id(true); @@ -79,11 +83,12 @@ if ($config['strict']) { } @setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); } + // Rate limiting -if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $config['strict']) { +if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $config['strict'])) { $skip_check = false; - $per_page = ($config['mc_antidos']['per_page']) ? $_SERVER['QUERY_STRING'] : ''; // if this is an api call we need to be careful not to time them out for those calls separately + $per_page = ''; $ajax_calls = array( array('api', 'getuserbalance'), array('api', 'getnavbardata'), @@ -96,9 +101,7 @@ if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $confi } $is_ajax_call = ($iac > 0) ? true : false; if ($is_ajax_call && $config['mc_antidos']['protect_ajax']) { - // we set this to navbar on purpose - if they screw with the REQUEST by adding more - // params it still gets added under navbar so multiple requests will still get capped - $per_page = 'navbar'; + $per_page = 'api'; } else if ($is_ajax_call && !$config['mc_antidos']['protect_ajax']) { // protect isn't on, we'll ignore it $skip_check = true; @@ -107,9 +110,13 @@ if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $confi } if (!$skip_check) { $mcad = new MemcacheAntiDos($config['mc_antidos'], $memcache, $_SERVER['REMOTE_ADDR'], $per_page, $config['memcache']); - $rate_limit_reached = $mcad->rateLimitRequest(); + $rate_limit_reached_site = $mcad->rateLimitSite(); + $rate_limit_reached_api = $mcad->rateLimitAPI(); + if ($rate_limit_reached_api && $is_ajax_call && $config['mc_antidos']['protect_ajax']) { + exit(header('HTTP/1.1 401 Unauthorized')); + } $error_page = $config['mc_antidos']['error_push_page']; - if ($rate_limit_reached == true) { + if ($rate_limit_reached_site == true) { if (!is_array($error_page) || count($error_page) < 1 || (empty($error_page['page']) && empty($error_page['action']))) { die("You are sending too many requests too fast!"); } else { @@ -120,6 +127,11 @@ if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled'] || $confi } } +// Quick config check +if (@$_SESSION['USERDATA']['is_admin'] && (!$config['skip_config_tests'])) { + require_once(INCLUDE_DIR. '/admin_checks.php'); +} + // Create our pages array from existing files if (is_dir(INCLUDE_DIR . '/pages/')) { foreach (glob(INCLUDE_DIR . '/pages/*.inc.php') as $filepath) { diff --git a/public/templates/mpos/login/default.tpl b/public/templates/mpos/login/default.tpl index b9c8ef56..b407e2a1 100644 --- a/public/templates/mpos/login/default.tpl +++ b/public/templates/mpos/login/default.tpl @@ -1,6 +1,5 @@
-

Login with existing account

From f56c18276afa99a9f6d72f7e878226fb1cd5b8b6 Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 28 Jan 2014 07:02:49 -0500 Subject: [PATCH 12/30] small fixes --- public/include/autoloader.inc.php | 4 ++-- public/include/config/security.inc.dist.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 5042e09e..f2df9ae4 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -71,8 +71,8 @@ require_once(INCLUDE_DIR . '/lib/scrypt.php'); // Include our versions require_once(INCLUDE_DIR . '/version.inc.php'); -if ($user->isAdmin(@$_SESSION['USERDATA']['id'])) { - //include_once(INCLUDE_DIR . '/admin_checks.inc.php'); +if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA']['id'])) { + include_once(INCLUDE_DIR . '/admin_checks.inc.php'); } ?> diff --git a/public/include/config/security.inc.dist.php b/public/include/config/security.inc.dist.php index 66612efe..8d1b3664 100644 --- a/public/include/config/security.inc.dist.php +++ b/public/include/config/security.inc.dist.php @@ -8,8 +8,8 @@ * Check -> Memcache configuration * Check -> Memcache anti resource-dos * - * Options Default Explanation - * ------- + ------- + ----------- + * Options Default Explanation + * ------- + ------- + ----------- * strict : true : Whether or not to use strict mode * __https_only : false : Requires/pushes to https * __mysql_filter : true : Uses a mysqli shim to use php filters on all incoming data From 9f6cf99aa3df78aabecb0b1d0c30ae78d4e1c14b Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 28 Jan 2014 08:08:53 -0500 Subject: [PATCH 13/30] small fixes --- public/include/admin_checks.php | 35 ++++++++++++++++++--------- public/include/classes/user.class.php | 2 +- public/include/pages/login.inc.php | 2 +- public/index.php | 2 +- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 1a28da32..2652659b 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -2,16 +2,17 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA']['id'])) { - if (!include_once(INCLUDE_DIR . '/lib/jsonRPCClient.php')) die('Unable to load libs'); - $notice = array(); $enotice = array(); $error = array(); - // setup some basic stuff for checking - $apache_user = posix_getuid(); - $apache_user = (function_exists('posix_getpwuid')) ? posix_getpwuid($apache_user) : $apache_user; + // setup some basic stuff for checking - getuid/getpwuid not available on mac/windows + $apache_user = 'unknown'; + if (substr_count(strtolower(PHP_OS), 'nix') > 0) { + $apache_user = (function_exists('posix_getuid')) ? posix_getuid() : 'unknown'; + $apache_user = (function_exists('posix_getpwuid')) ? posix_getpwuid($apache_user) : $apache_user; + } // setup checks // check if memcache isn't available but enabled in config -> error @@ -71,19 +72,29 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ $error[] = "strict or mc_antidos are enabled and memcache is not, memcache is required to use these."; } // poke stratum using gettingstarted details -> enotice - $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($socket !== false) { - $address = @gethostbyname($config['gettingstarted']['stratumurl']); - $result = @socket_connect($socket, $address, $config['gettingstarted']['stratumport']); - if ($result !== 1) { + if (substr_count(strtolower(PHP_OS), 'nix') > 0) { + // unix *poke* + $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($socket !== false) { + $address = @gethostbyname($config['gettingstarted']['stratumurl']); + $result = @socket_connect($socket, $address, $config['gettingstarted']['stratumport']); + if ($result !== 1) { + $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; + } + $close = @socket_close($socket); + } + } else { + // mac/windows *poke* + if (! $fp = @fsockopen($config['gettingstarted']['stratumurl'],$config['gettingstarted']['stratumport'],$errCode,$errStr,1)) { $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; } - $close = @socket_close($socket); + @fclose($fp); } + // security checks // strict not on -> notice if (!$config['strict']) { - $notice[] = "strict is disabled - if you have memcache, you should turn this on."; + $notice[] = "Strict is disabled - if you have memcache, you should turn this on."; } // salts too short -> notice, salts default -> error if ((strlen(SALT) < 24) || (strlen(SALTY) < 24) || SALT == 'PLEASEMAKEMESOMETHINGRANDOM' || SALTY == 'THISSHOULDALSOBERRAANNDDOOM') { diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 1c0feee0..3d1366b3 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -493,7 +493,7 @@ class User extends Base { private function createSession($username) { $this->debug->append("STA " . __METHOD__, 4); $this->debug->append("Log in user to _SESSION", 2); - if ($this->config['strict']) { + if ($this->config['strict'] && $this->config['memcache']['enabled']) { session_regenerate_id(true); $_SESSION['AUTHENTICATED'] = '1'; // $this->user from checkUserPassword diff --git a/public/include/pages/login.inc.php b/public/include/pages/login.inc.php index 84964672..d80dd08c 100644 --- a/public/include/pages/login.inc.php +++ b/public/include/pages/login.inc.php @@ -29,7 +29,7 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; - if ($config['strict']) { + if ($config['strict'] && $config['memcache']['enabled']) { $update = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); $session->regen_session_id(); $update['sid'] = session_id(); diff --git a/public/index.php b/public/index.php index 61a5a327..cb99e3fd 100644 --- a/public/index.php +++ b/public/index.php @@ -128,7 +128,7 @@ if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $conf } // Quick config check -if (@$_SESSION['USERDATA']['is_admin'] && (!$config['skip_config_tests'])) { +if (@$_SESSION['USERDATA']['is_admin'] && !@$config['skip_config_tests']) { require_once(INCLUDE_DIR. '/admin_checks.php'); } From 614b5b1dbb7d6bc1640d74ca3a291e71777f2f89 Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 28 Jan 2014 08:19:58 -0500 Subject: [PATCH 14/30] of all the pages to miss it on --- public/include/config/security.inc.dist.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/include/config/security.inc.dist.php b/public/include/config/security.inc.dist.php index 8d1b3664..88d43df0 100644 --- a/public/include/config/security.inc.dist.php +++ b/public/include/config/security.inc.dist.php @@ -1,4 +1,6 @@ Date: Tue, 28 Jan 2014 10:31:53 -0500 Subject: [PATCH 15/30] security config mask --- public/index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/index.php b/public/index.php index cb99e3fd..7a972a8a 100644 --- a/public/index.php +++ b/public/index.php @@ -41,7 +41,8 @@ define("BASEPATH", dirname(__FILE__) . "/"); // Include our configuration (holding defines for the requires) if (!include_once(BASEPATH . 'include/config/global.inc.php')) die('Unable to load site configuration'); -if (!include_once(BASEPATH . 'include/config/security.inc.php')) die('Unable to load security configuration'); +if (!include_once(BASEPATH . 'include/config/security.inc.dist.php')) die('Unable to load security configuration'); +if (@file_exists(BASEPATH . 'include/config/security.inc.php')) include_once(BASEPATH . 'include/config/security.inc.php'); // switch to https if config option is enabled $hts = ($config['strict__https_only'] && (!empty($_SERVER['QUERY_STRING']))) ? "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']."?".$_SERVER['QUERY_STRING'] : "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']; From 3efe979ae3d6fd5326990a82433520c85ada389b Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 28 Jan 2014 14:24:48 -0500 Subject: [PATCH 16/30] Switch config over to wiki, yay --- public/include/config/global.inc.dist.php | 533 ++++---------------- public/include/config/security.inc.dist.php | 104 +--- 2 files changed, 124 insertions(+), 513 deletions(-) diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 63c44b83..83c35b62 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -3,60 +3,42 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; /** * Do not edit this unless you have confirmed that your config has been updated! - * This is used in the version check to ensure you run the latest version of the configuration file. - * Once you upgraded your config, change the version here too. + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-config-version **/ $config['version'] = '0.0.7'; /** * Unless you disable this, we'll do a quick check on your config first. + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-config-check */ $config['skip_config_tests'] = false; -// Our include directory for additional features -define('INCLUDE_DIR', BASEPATH . 'include'); -// Our class directory -define('CLASS_DIR', INCLUDE_DIR . '/classes'); - -// Our pages directory which takes care of -define('PAGES_DIR', INCLUDE_DIR . '/pages'); - -// Our theme folder holding all themes -define('THEME_DIR', BASEPATH . 'templates'); - -// Set debugging level for our debug class -// Values valid from 0 (disabled) to 5 (most verbose) +/** + * Defines + * Debug setting and salts for hashing passwords + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-defines--salts + */ define('DEBUG', 0); - -// SALT used to hash passwords define('SALT', 'PLEASEMAKEMESOMETHINGRANDOM'); define('SALTY', 'THISSHOULDALSOBERRAANNDDOOM'); +define('INCLUDE_DIR', BASEPATH . 'include'); +define('CLASS_DIR', INCLUDE_DIR . '/classes'); +define('PAGES_DIR', INCLUDE_DIR . '/pages'); +define('THEME_DIR', BASEPATH . 'templates'); + /** - * Underlying coin algorithm that you are mining on. Set this to whatever your coin needs: - * - * Options: - * sha256d : SHA coins like Bitcoin - * scrypt : Scrypt based coins like Litecoin - * Default: - * scrypt : Scrypt is default + * Coin Algorithm + * Algorithm used by this coin, sha256d or scrypt + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-algorithm **/ $config['algorithm'] = 'scrypt'; /** * Database configuration - * - * A MySQL database backend is required for MPOS. - * Also ensure the database structure is imported! - * The SQL file should be included in this project under the `sql` directory - * - * Default: - * host = 'localhost' - * port = 3306 - * user = 'someuser' - * pass = 'somepass' - * name = 'mpos' + * MySQL database configuration + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-database-configuration **/ $config['db']['host'] = 'localhost'; $config['db']['user'] = 'someuser'; @@ -65,17 +47,9 @@ $config['db']['port'] = 3306; $config['db']['name'] = 'mpos'; /** - * Local wallet RPC configuration - * - * MPOS uses the RPC backend to fetch transactions, blocks - * and various other things. They need to match your coind RPC - * configuration. - * - * Default: - * type = 'http' - * host = 'localhost:19334' - * username = 'testnet' - * password = 'testnet' + * Local wallet RPC + * RPC configuration for your daemon/wallet + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-local-wallet-rpc **/ $config['wallet']['type'] = 'http'; $config['wallet']['host'] = 'localhost:19334'; @@ -83,23 +57,9 @@ $config['wallet']['username'] = 'testnet'; $config['wallet']['password'] = 'testnet'; /** - * Payout of liquid assets - * - * Explanation: - * Running pools, especially those with active fees, will build up a good - * amount of liquid assets that can be used by pool operators. If you wish - * to automatically send your assets to a offline wallet, set your account - * address, reserves and thresholds here. - * - * Options: - * address : The address of the wallet to the address you'd like to receive the coins in - * reserve : The amount you'd like to remain in the wallet. Recommended is at least 1 block value - * threshold : The amount of coins you'd like to send per batch minimum. Once exceeded, this is sent - * to the offline wallet address specified. - * Default: - * addresss : empty - * reserve : 50 - * threshold : 25 + * Cold Wallet / Liquid Assets + * Automatically send liquid assets to a cold wallet + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-liquid-assets--cold-wallet **/ $config['coldwallet']['address'] = ''; $config['coldwallet']['reserve'] = 50; @@ -107,11 +67,8 @@ $config['coldwallet']['threshold'] = 5; /** * Getting Started Config - * - * This is displayed on GettingStarted Page - * to make it more dynamic - * - * + * Shown to users in the 'Getting Started' section + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-getting-started **/ $config['gettingstarted']['coinname'] = 'Litecoin'; $config['gettingstarted']['coinurl'] = 'http://www.litecoin.org'; @@ -119,355 +76,151 @@ $config['gettingstarted']['stratumurl'] = ''; $config['gettingstarted']['stratumport'] = '3333'; /** - * API configuration to fetch prices for set currency - * - * Explanation: - * MPOS will try to fetch the current exchange rates - * from this API URL/target. Currently btc-e and coinchoose - * are supported in MPOS. If you want to remove the trade - * header just set currency to an empty string. - * - * Default (btc-e.com): - * url = `https://btc-e.com` - * target = `/api/2/ltc_usd/ticker` - * currency = `USD` - * - * Optional (coinchoose.com): - * url = `http://www.coinchoose.com` - * target = `/api.php` - * currency = `BTC` - * - * Optional (cryptsy.com): - * url = `http://pubapi.cryptsy.com` - * currency = `BTC` - * target = `/api.php?method=marketdata` + * Ticker API + * Fetch exchange rates via an API + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-ticker-api **/ $config['price']['url'] = 'https://btc-e.com'; $config['price']['target'] = '/api/2/ltc_usd/ticker'; $config['price']['currency'] = 'USD'; /** - * Automatic payout thresholds - * - * These values define the min and max settings - * that can be entered by a user. - * Defaults: - * `min` = `1` - * `max` = `250` + * Automatic Payout Thresholds + * Minimum and Maximum auto payout amount + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-automatic-payout-thresholds **/ $config['ap_threshold']['min'] = 1; $config['ap_threshold']['max'] = 250; /** * Donation thresholds - * - * You can define a min and max values for you users - * donation settings here. - * - * Defaults: - * `min` = `1` + * Minimum donation amount in percent + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-donation-thresholds **/ $config['donate_threshold']['min'] = 1; /** - * Account specific settings - * - * Explanation - * Invitations will allow your users to invite new members to join the pool. - * After sending a mail to the invited user, they can register using the token - * created. Invitations can be enabled and disabled through the admin panel. - * Sent invitations are listed on the account invitations page. - * - * You can limit the number of registrations send per account via configuration - * variable. - * - * Options: - * count : Maximum invitations a user is able to send - * - * Defaults: - * count : 5 + * Account Specific Settings + * Settings for each user account + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-account-specific-settings **/ $config['accounts']['invitations']['count'] = 5; -// Currency system used in this pool, default: `LTC` +/** + * Currency + * Shorthand name for the currency + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-currency + */ $config['currency'] = 'LTC'; /** - * Coin Target in seconds - * - * Explanation - * Target time for coins to be generated - * - * Fastcoin: 12 seconds - * Litecoin: 2,5 minutes = 150 seconds - * Feathercoin: 2,5 minutes = 150 seconds - * Bitcoin: 10 minutes = 600 seconds - * + * Coin Target + * Target time for coins to be generated + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-coin-target **/ $config['cointarget'] = '150'; /** - * Diff change every X Blocks - * - * Explanation - * Amount of Blocks until Difficulty change - * - * Fastcoin: 300 Blocks - * Litecoin: 2016 Blocks - * Bitcoin: 2016 Blocks - * + * Coin Diff Change + * Amount of blocks between difficulty changes + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-coin-diff-change **/ $config['coindiffchangetarget'] = 2016; /** - * Default transaction fee to apply to user transactions - * - * Explanation - * The coin daemon applies transaction fees to young coins. - * Since we are unable to find out what the exact fee was we set - * a default value here which is applied to both manual and auto payouts. - * If this is not set, no fee is applied in the transactions history but - * the user might still see them when the coins arrive. - * You can set two different transaction fees for manual and auto payouts. - * - * Default: - * txfee_auto = 0.1 - * txfee_manual = 0.1 - * + * TX Fees + * Fees applied to transactions + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-tx-fees **/ $config['txfee_auto'] = 0.1; $config['txfee_manual'] = 0.1; -// Payout a block bonus to block finders, default: 0 (disabled) -// This bonus is paid by the pool operator, it is not deducted from the block payout! +/** + * Block Bonus + * Bonus in coins of block bonus + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-block-bonus + */ $config['block_bonus'] = 0; /** - * Payout system in use - * - * This will modify some templates and activate the - * appropriate crons. Only ONE payout system at a time - * is supported! - * - * Available options: - * prop: Proportional payout system - * pps : Pay Per Share payout system - * pplns : Pay Per Last N Shares payout system - * - * Default: - * prop -**/ + * Payout System + * Payout system chosen + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-payout-system + **/ $config['payout_system'] = 'prop'; /** - * Round purging - * - * Explanation: - * As soon as a round is finished, shares of that rate are archived (see below) - * and deleted from the `shares` table. Due to a large amount of shares in a - * single round, this can take a very long time. To reduce server load and allow - * other systems to access the DB during this high-load time, the DELETE - * calls are being limited to a number of rows. Then the process sleeps and - * continues to delete shares until all shares have been purged. - * - * You can adjust some purging settings here in order to improve your overall - * site performance during round ends. Keep in mind that decreasing shares/time - * will make the cron run longer but at least keeps your site active. Vice versa - * higher numbers allow for a faster deletion but might affect the live site. - * - * This system is also used when purging archived shares. - * - * Available Options: - * sleep : Time to sleep between delete calls - * shares : How many shares to delete at one time - * - * Default: - * sleep : 5 seconds - * shares : 500000 + * Round Purging + * Round share purging configuration + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-round-purging **/ $config['purge']['sleep'] = 1; $config['purge']['shares'] = 25000; /** - * Archiving configuration for debugging - * - * Explanation: - * By default, we don't need to archive for a long time. PPLNS and Hashrate - * calculations rely on this archive, but all shares past a certain point can - * safely be deleted. - * - * To ensure we have enough shares on stack for PPLNS, this - * is set to the past 10 rounds. Even with lucky ones in between those should - * fit the PPLNS target. On top of that, even if we have more than 10 rounds, - * we still keep the last maxage shares to ensure we can calculate hashrates. - * Both conditions need to be met in order for shares to be purged from archive. - * - * Proportional mode will only keep the past 24 hours. These are required for - * hashrate calculations to work past a round, hence 24 hours was selected as - * the default. You may want to increase the time for debugging, then add any - * integer reflecting minutes of shares to keep. - * - * Availabe Options: - * maxrounds : PPLNS, keep shares for maxrounds - * maxage : PROP and PPLNS, delete shares older than maxage minutes - * - * Default: - * maxrounds = 10 - * maxage = 60 * 24 (24h) + * Share Archiving + * Share archiving configuration details + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-archiving **/ $config['archive']['maxrounds'] = 10; $config['archive']['maxage'] = 60 * 24; -// Pool fees applied to users in percent, default: 0 (disabled) + +/** + * Pool Fees + * Fees applied to users + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-pool-fees + */ $config['fees'] = 0; /** - * PPLNS requires some settings to run properly. First we need to define - * a default shares count that is applied if we don't have a proper type set. - * Different dynamic types can be applied, or you can run a fixed scheme. - * - * Explanation - * - * PPLNS can run on two different payouts: fixed and blockavg. Each one - * defines a different PPLNS target. - * - * Fixed means we will be looking at the shares setup in the default - * setting. There is no automatic adjustments to the PPLNS target, - * all users will be paid out proportionally to that target. - * - * Blockavg will look at the last blockcount blocks shares and take - * the average as the PPLNS target. This will be automatically adjusted - * when difficulty changes and more blocks are available. This keeps the - * target dynamic but still traceable. - * - * If you use the fixed type it will use $config['pplns']['shares']['default'] - * for target calculations, if you use blockavg type it will use - * $config['pplns']['blockavg']['blockcount'] blocks average for target - * calculations. - * - * default : Default target shares for PPLNS - * type : Payout type used in PPLNS - * blockcount : Amount of blocks to check for avg shares - * - * Available Options: - * default : amount of shares, integeger - * type : blockavg or fixed - * blockcount : amount of blocks, any integer - * - * Defaults: - * default = 4000000 - * type = `blockavg` - * blockcount = 10 - **/ -/** - * $config['pplns']['shares']['type'] = 'dynamic'; - * Dynamic target adjustment allows the blockavg target to adjust faster to share counts - * while still tracking round share averages by using a percentage of the current round shares - * to alter the pplns blockavg target this is useful with the nature of many alt coins low and fast - * adjusting difficulties and quick round times - * reverse_payout is useful to even out payouts for fast round times when even steady miners - * are missing share submissions for the current round -**/ + * PPLNS + * Pay Per Last N Shares + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-pplns-settings + */ $config['pplns']['shares']['default'] = 4000000; $config['pplns']['shares']['type'] = 'blockavg'; $config['pplns']['blockavg']['blockcount'] = 10; -$config['pplns']['reverse_payout'] = false; // add user shares from archive even if user not in current round -$config['pplns']['dynamic']['percent'] = 30; // percentage of round shares factored into block average when using dynamic type - -// Pool target difficulty as set in pushpoold configuration file -// Please also read this for stratum: https://github.com/TheSerapher/php-mpos/wiki/FAQ -$config['difficulty'] = 20; - +$config['pplns']['reverse_payout'] = false; +$config['pplns']['dynamic']['percent'] = 30; /** - * This defines how rewards are paid to users. - * - * Explanation: - * - * Proportional + PPLNS Payout System - * When running a pool on fixed mode, each block will be paid - * out as defined in `reward`. If you wish to pass transaction - * fees inside discovered blocks on to user, set this to `block`. - * This is really helpful for altcoins with dynamic block values! - * - * PPS Payout System - * If set to `fixed`, all PPS values are based on the `reward` setting. - * If you set it to `block` you will calculate the current round based - * on the previous block value. The idea is to pass the block of the - * last round on to the users. If no previous block is found, PPS value - * will fall back to the fixed value set in `reward`. Ensure you don't - * overpay users in the first round! - * - * Available options: - * reward_type: - * fixed : Fixed value according to `reward` setting - * block : Dynamic value based on block amount - * reward: - * float value : Any value of your choice but should reflect base block values - * - * Default: - * reward_type = `fixed` - * reward = 50 - * + * Difficulty + * Difficulty setting for stratum/pushpool + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-pool-target-difficulty + */ +$config['difficulty'] = 20; + +/** + * Block Reward + * Block reward configuration details + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-reward-settings **/ $config['reward_type'] = 'block'; $config['reward'] = 50; -// Confirmations per block required to credit transactions, default: 120 -// Do NOT touch this unless you know what you are doing! Please check your coin for the -// appropriate value here, but most should work with this. +/** + * Confirmations + * Credit and Network confirmation settings + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-confirmations + */ $config['confirmations'] = 120; -// Confirmations per block required in network to confirm its transactions, default: 120 -// Do NOT touch this unless you know what you are doing! Please check your coin for the -// appropriate value here, but most should work with this. $config['network_confirmations'] = 120; - /** - * Available pps options: - * reward_type: - * fixed : Fixed value according to `reward` setting - * blockavg : Dynamic value based on average of x number of block rewards - * block : Dynamic value based on LAST block amount - * reward: - * float value : Any value of your choice but should reflect base block values - * blockcount : amount of blocks to average, any integer - * Default: - * pps_reward_type = `fixed` default $config['pps']['reward']['default'] - * reward = 50 - * +/** + * PPS + * Pay Per Share configuration details + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-pps-settings **/ $config['pps']['reward']['default'] = 50; $config['pps']['reward']['type'] = 'blockavg'; $config['pps']['blockavg']['blockcount'] = 10; /** - * Memcache configuration - * - * To disable memcache set option $config['memcache']['enabled'] = false - * After disable memcache installation of memcache is not required. - * - * Please note that a memcache is greatly increasing performance - * when combined with the `statistics.php` cronjob. Disabling this - * is not recommended in a live environment! - * - * Explanations - * enabled : Disable (false) memcache for debugging or enable (true) it - * host : Host IP or hostname - * port : memcache port - * keyprefix : Must be changed for multiple MPOS instances on one host - * expiration : Default expiration time in seconds of all cached keys. - * Increase if caches expire too fast. - * splay : Default randomizer for expiration times. - * This will spread expired keys across `splay` seconds. - * - * Default: - * enabled = `true` - * host = `localhost` - * port = 11211 - * keyprefix = `mpos_` - * expiration = 90 - * splay = 15 + * Memcache + * Memcache configuration details + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-memcache **/ $config['memcache']['enabled'] = true; $config['memcache']['host'] = 'localhost'; @@ -476,44 +229,10 @@ $config['memcache']['keyprefix'] = 'mpos_'; $config['memcache']['expiration'] = 90; $config['memcache']['splay'] = 15; - /** - * Cookie configuration - * - * You can configure the cookie behaviour to secure your cookies more than the PHP defaults - * - * For multiple installations of MPOS on the same domain you must change the cookie path. - * - * Explanation: - * duration: - * the amount of time, in seconds, that a cookie should persist in the users browser. - * 0 = until closed; 1440 = 24 minutes. Check your php.ini 'session.gc_maxlifetime' value - * and ensure that it is at least the duration specified here. - * - * domain: - * the only domain name that may access this cookie in the browser - * - * path: - * the highest path on the domain that can access this cookie; i.e. if running two pools - * from a single domain you might set the path /ltc/ and /ftc/ to separate user session - * cookies between the two. - * - * httponly: - * marks the cookie as accessible only through the HTTP protocol. The cookie can't be - * accessed by scripting languages, such as JavaScript. This can help to reduce identity - * theft through XSS attacks in most browsers. - * - * secure: - * marks the cookie as accessible only through the HTTPS protocol. If you have a SSL - * certificate installed on your domain name then this will stop a user accidentally - * accessing the site over a HTTP connection, without SSL, exposing their session cookie. - * - * Default: - * duration = '1440' - * domain = '' - * path = '/' - * httponly = true - * secure = false + * Cookies + * Cookie configuration details + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-cookies **/ $config['cookie']['duration'] = '1440'; $config['cookie']['domain'] = ''; @@ -522,50 +241,18 @@ $config['cookie']['httponly'] = true; $config['cookie']['secure'] = false; /** - * Enable or disable the Smarty cache - * - * Explanation: - * Smarty implements a file based cache for all HTML output generated - * from dynamic scripts. It can be enabled to cache the HTML data on disk, - * future request are served from those cache files. - * - * This may or may not work as expected, in general Memcache is used to cache - * all data so rendering the page should not take too long anyway. - * - * You can test this out and enable (1) this setting but it's not guaranteed to - * work with MPOS. - * - * Ensure that the folder `templates/cache` is writeable by the web server! - * - * cache = Enable/Disable the cache - * cache_lifetime = Time to keep files in seconds before updating them - * - * Options: - * cache: - * 0 = disabled - * 1 = enabled - * cache_lifetime: - * time in seconds - * - * Defaults: - * cache = 0, disabled - * cache_lifetime = 30 seconds + * Smarty Cache + * Enable smarty cache and cache length + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-smarty-cache **/ $config['smarty']['cache'] = 0; $config['smarty']['cache_lifetime'] = 30; /** - * System load setting - * - * This will disable loading of some API calls in case the system - * loads exceeds the defined max setting. Useful to temporarily suspend - * live statistics on a server that is too busy to deal with requests. - * - * Options - * max = float, maximum system load - * - * Defaults: - * max = 10.0 + * System load + * Disable some calls when high system load + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-system-load **/ $config['system']['load']['max'] = 10.0; -?> + +?> \ No newline at end of file diff --git a/public/include/config/security.inc.dist.php b/public/include/config/security.inc.dist.php index 88d43df0..6856e601 100644 --- a/public/include/config/security.inc.dist.php +++ b/public/include/config/security.inc.dist.php @@ -2,28 +2,9 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; /** - * Strict is a set of extra security options can use that when enabled can help protect against - * a few different types of attacks. - * - * You must have Memcache enabled and configured & Memcache anti-dos configured to use this! - * - * Check -> Memcache configuration - * Check -> Memcache anti resource-dos - * - * Options Default Explanation - * ------- + ------- + ----------- - * strict : true : Whether or not to use strict mode - * __https_only : false : Requires/pushes to https - * __mysql_filter : true : Uses a mysqli shim to use php filters on all incoming data - * __verify_client : true : Verifies the client using specified settings - * __verify_client_ip : true : If the client request suddenly switches IP, trigger a failure - * __verify_client_useragent : true : If the client request suddenly switches Useragent, trigger a failure - * __verify_client_sessionid : true : If the client request suddenly switches SessionID, trigger a failure - * __verify_client_fails : 0 : Maximum number of client-side inconsistencies to accept before revoking sessions - * __verify_server : false : Verifies the server is valid for this request - * __bind_protocol : https : Server validate protocol; http or https - * __bind_host : '' : Server validate host; ie. your domain or subdomain - * __bind_port : 443 : Server validate port; 80 / 443 / something else + * Strict Mode + * Extra security options that can help protect against a few different types of attacks + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-strict-mode **/ $config['strict'] = true; $config['strict__https_only'] = false; @@ -39,33 +20,9 @@ $config['strict__bind_host'] = ''; $config['strict__bind_port'] = 443; /** - * Memcache anti resource-dos protection / request rate limiting - * - * Explanation: - * Because bots/angry users can just fire away at pages or f5 us to death, we can attempt to rate limit requests - * using memcache - now shares data with session manager. - * - * Options: - * enabled = Whether or not we will try to rate limit requests - * protect_ajax = If enabled, we will also watch the ajax calls for rate limiting and kill bad requests - * ajax_hits_additive = If enabled, ajax hits will count towards the site counter as well as the ajax counter - * flush_seconds_api = Number of seconds between each flush of user/ajax counter - * rate_limit_api = Number of api requests allowed per flush_seconds_api - * flush_seconds_site = Number of seconds between each flush of user/site counter - * rate_limit_site = Number of site requests allowed per flush_seconds_site - * ignore_admins = Ignores the rate limit for admins - * error_push_page = Page/action array to push users to a specific page, look in the URL! - * Empty = 'You are sending too many requests too fast!' on a blank page - * Default: - * enabled = true - * protect_ajax = true - * ajax_hits_additive = false - * flush_seconds_api = 60 - * rate_limit_api = 20 - * flush_seconds_site = 60 - * rate_limit_site = 30 - * ignore_admins = true - * error_push_page = array('page' => 'error', 'action' => 'ratelimit'); + * Memcache Rate Limiting + * Rate limit requests using Memcache + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-memcache-rate-limiting */ $config['mc_antidos']['enabled'] = true; $config['mc_antidos']['protect_ajax'] = true; @@ -78,38 +35,16 @@ $config['mc_antidos']['ignore_admins'] = true; $config['mc_antidos']['error_push_page'] = array('page' => 'error', 'action' => 'ratelimit'); /** - * CSRF protection config - * - * Explanation: - * To help protect against CSRF, we can generate a hash that changes every minute - * and is unique for each user/IP and page or use, and check against that when a - * form is submitted. - * - * Options: - * enabled = Whether or not we will generate/check for valid CSRF tokens - * Default: - * enabled = true + * CSRF Protection + * Enable or disable CSRF protection + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-csrf-protection */ $config['csrf']['enabled'] = true; /** * E-mail confirmations for user actions - * - * Explanation: - * To increase security for users, account detail changes can require - * an e-mail confirmation prior to performing certain actions. - * - * Options: - * enabled : Whether or not to require e-mail confirmations - * details : Require confirmation to change account details - * withdraw : Require confirmation to manually withdraw/payout - * changepw : Require confirmation to change password - * - * Default: - * enabled = true - * details = true - * withdraw = true - * changepw = true + * Two-factor confirmation for user actions + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-e-mail-confirmations */ $config['twofactor']['enabled'] = true; $config['twofactor']['options']['details'] = true; @@ -117,20 +52,9 @@ $config['twofactor']['options']['withdraw'] = true; $config['twofactor']['options']['changepw'] = true; /** - * Lock account after maximum failed logins - * - * Explanation: - * To avoid accounts being hacked by brute force attacks, - * set a maximum amount of failed login or pin entry attempts before locking - * the account. They will need to contact site support to re-enable the account. - * - * This also applies for invalid PIN entries, which is covered by the pin option. - * - * Workers are not affected by this lockout, mining will continue as usual. - * - * Default: - * login = 3 - * pin = 3 + * Lock account after X + * Lock accounts after X attempts + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-lock-accounts-after-failed-logins **/ $config['maxfailed']['login'] = 3; $config['maxfailed']['pin'] = 3; From 74dec2796d46f41755919cc08b8e7f2e03d6a780 Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 28 Jan 2014 15:45:24 -0500 Subject: [PATCH 17/30] Added last login time/ip address popup on login w/ close button Info/blue if your ip matches, warning/yellow if not --- public/include/classes/user.class.php | 18 ++++++++++++++---- public/index.php | 14 ++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 3d1366b3..e3a543be 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -43,6 +43,9 @@ class User extends Base { public function getUserIp($id) { return $this->getSingle($id, 'loggedIp', 'id'); } + public function getLastLogin($id) { + return $this->getSingle($id, 'last_login', 'id'); + } public function getEmail($email) { return $this->getSingle($email, 'email', 'email', 's'); } @@ -138,9 +141,13 @@ class User extends Base { return false; } if ($this->checkUserPassword($username, $password)) { - $this->updateLoginTimestamp($this->getUserId($username)); - $this->createSession($username); - if ($this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR'])) { + $uid = $this->getUserId($username); + $this->updateLoginTimestamp($uid); + $getIPAddress = $this->getUserIp($uid); + $setIPAddress = $this->setUserIp($uid, $_SERVER['REMOTE_ADDR']); + $lastLoginTime = $this->getLastLogin($uid); + $this->createSession($username, $getIPAddress, $lastLoginTime); + if ($setIPAddress) { // send a notification if success_login is active $uid = $this->getUserId($username); $notifs = new Notification(); @@ -490,9 +497,12 @@ class User extends Base { * @param username string Username to create session for * @return none **/ - private function createSession($username) { + private function createSession($username, $lastIP='', $lastLoginTime='') { $this->debug->append("STA " . __METHOD__, 4); $this->debug->append("Log in user to _SESSION", 2); + if (!empty($lastIP) && (!empty($lastLoginTime))) { + $_SESSION['last_ip_pop'] = array($lastIP, $lastLoginTime); + } if ($this->config['strict'] && $this->config['memcache']['enabled']) { session_regenerate_id(true); $_SESSION['AUTHENTICATED'] = '1'; diff --git a/public/index.php b/public/index.php index 7a972a8a..fbcc0bcb 100644 --- a/public/index.php +++ b/public/index.php @@ -128,6 +128,20 @@ if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $conf } } +// Got past rate limiter and session manager, show last logged in popup if it's still set +if (@$_GET['clp'] == 1 && @$_SESSION['last_ip_pop']) unset($_SESSION['last_ip_pop']); +if (count(@$_SESSION['last_ip_pop']) == 2) { + $data = $_SESSION['last_ip_pop']; + $ip = filter_var($data[0], FILTER_VALIDATE_IP); + $time = date("l, F jS \a\\t g:i a", $data[1]); + $closelink = "Close"; + if (@$_SESSION['AUTHENTICATED'] && $_SESSION['last_ip_pop'][0] !== $_SERVER['REMOTE_ADDR']) { + $_SESSION['POPUP'][] = array('CONTENT' => "You last logged in from $ip on $time $closelink", 'TYPE' => 'warning'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => "You last logged in from $ip on $time $closelink", 'TYPE' => 'info'); + } +} + // Quick config check if (@$_SESSION['USERDATA']['is_admin'] && !@$config['skip_config_tests']) { require_once(INCLUDE_DIR. '/admin_checks.php'); From 56ad9266d39b328d7b9b1415bf07b7929ed66be1 Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 03:55:51 -0500 Subject: [PATCH 18/30] last login time not this login time --- public/include/classes/user.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index e3a543be..b71119ac 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -142,10 +142,10 @@ class User extends Base { } if ($this->checkUserPassword($username, $password)) { $uid = $this->getUserId($username); + $lastLoginTime = $this->getLastLogin($uid); $this->updateLoginTimestamp($uid); $getIPAddress = $this->getUserIp($uid); $setIPAddress = $this->setUserIp($uid, $_SERVER['REMOTE_ADDR']); - $lastLoginTime = $this->getLastLogin($uid); $this->createSession($username, $getIPAddress, $lastLoginTime); if ($setIPAddress) { // send a notification if success_login is active From c2b1c6869901b7b6e0208a0d33cc50d5035f6c3b Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 05:20:06 -0500 Subject: [PATCH 19/30] added check if we can write config files to admin_checks, we shouldnt be able to --- public/include/admin_checks.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 2652659b..094555ce 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -44,6 +44,11 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ if (!is_writable(THEME_DIR.'/compile')) { $error[] = "templates/compile folder is not writable for uid {$apache_user['name']}"; } + // check if we can write the config files, we should NOT be able to -> error + if (is_writable(INCLUDE_DIR.'/config/global.inc.php') || is_writable(INCLUDE_DIR.'/config/global.inc.dist.php') || + is_writable(INCLUDE_DIR.'/config/security.inc.php') || is_writable(INCLUDE_DIR.'/config/security.inc.dist.php')) { + $error[] = "Your config files SHOULD NOT be writable to this user!"; + } // check if daemon can connect -> error try { if ($bitcoin->can_connect() !== true) { From 568445845a796c1e8645c9533817edcc2928c9ca Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 07:34:50 -0500 Subject: [PATCH 20/30] changes DEBUG SALT and SALTY from defines to variables switched that in all places used (class loads mostly) moved all includes at the beginning of index into bootstrap moves *_PATH defines from config to bootstrap config now uses defaults first, then user config --- public/include/admin_checks.php | 4 +-- public/include/bootstrap.php | 28 +++++++++++++++++++ .../include/classes/bitcoinwrapper.class.php | 2 +- public/include/classes/csrftoken.class.php | 4 +-- public/include/classes/debug.class.php | 2 +- public/include/classes/user.class.php | 2 +- public/include/config/global.inc.dist.php | 11 ++------ public/include/smarty_globals.inc.php | 2 +- public/index.php | 18 ++---------- tests/unit/config/SampleTest.php | 4 +-- 10 files changed, 44 insertions(+), 33 deletions(-) create mode 100644 public/include/bootstrap.php diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 094555ce..d1c099cd 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -102,8 +102,8 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ $notice[] = "Strict is disabled - if you have memcache, you should turn this on."; } // salts too short -> notice, salts default -> error - if ((strlen(SALT) < 24) || (strlen(SALTY) < 24) || SALT == 'PLEASEMAKEMESOMETHINGRANDOM' || SALTY == 'THISSHOULDALSOBERRAANNDDOOM') { - if (SALT == 'PLEASEMAKEMESOMETHINGRANDOM' || SALTY == 'THISSHOULDALSOBERRAANNDDOOM') { + if ((strlen($config['SALT']) < 24) || (strlen($config['SALTY']) < 24) || $config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { + if ($config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { $error[] = "You absolutely SHOULD NOT leave your SALT or SALTY default"; } else { $notice[] = "SALT or SALTY is too short, they should be more than 24 characters and changing them will require registering again."; diff --git a/public/include/bootstrap.php b/public/include/bootstrap.php new file mode 100644 index 00000000..98cf6d55 --- /dev/null +++ b/public/include/bootstrap.php @@ -0,0 +1,28 @@ +Quick Start Guide"; + +// Include our configuration (holding defines for the requires) +if (!include_once(BASEPATH . 'include/config/global.inc.dist.php')) die('Unable to load base global config - '.$quickstartlink); +if (!@include_once(BASEPATH . 'include/config/global.inc.php')) die('Unable to load your global config - '.$quickstartlink); + +// load our security configs +if (!include_once(BASEPATH . 'include/config/security.inc.dist.php')) die('Unable to load base security config - '.$quickstartlink); +if (@file_exists(BASEPATH . 'include/config/security.inc.php')) include_once(BASEPATH . 'include/config/security.inc.php'); + +// Our default template to load, pages can overwrite this later +$master_template = 'master.tpl'; + +// Load Classes, they name defines the $ variable used +// We include all needed files here, even though our templates could load them themself +require_once(INCLUDE_DIR . '/autoloader.inc.php'); + +?> \ No newline at end of file diff --git a/public/include/classes/bitcoinwrapper.class.php b/public/include/classes/bitcoinwrapper.class.php index fe913ee2..544cecff 100644 --- a/public/include/classes/bitcoinwrapper.class.php +++ b/public/include/classes/bitcoinwrapper.class.php @@ -73,4 +73,4 @@ class BitcoinWrapper extends BitcoinClient { } // Load this wrapper -$bitcoin = new BitcoinWrapper($config['wallet']['type'], $config['wallet']['username'], $config['wallet']['password'], $config['wallet']['host'], DEBUG, $debug, $memcache); +$bitcoin = new BitcoinWrapper($config['wallet']['type'], $config['wallet']['username'], $config['wallet']['password'], $config['wallet']['host'], $config['DEBUG'], $debug, $memcache); diff --git a/public/include/classes/csrftoken.class.php b/public/include/classes/csrftoken.class.php index bdcb0821..13e20955 100644 --- a/public/include/classes/csrftoken.class.php +++ b/public/include/classes/csrftoken.class.php @@ -97,8 +97,8 @@ class CSRFToken Extends Base { $csrftoken = new CSRFToken(); $csrftoken->setDebug($debug); $csrftoken->setMysql($mysqli); -$csrftoken->setSalt(SALT); -$csrftoken->setSalty(SALTY); +$csrftoken->setSalt($config['SALT']); +$csrftoken->setSalty($config['SALTY']); $csrftoken->setMail($mail); $csrftoken->setUser($user); $csrftoken->setToken($oToken); diff --git a/public/include/classes/debug.class.php b/public/include/classes/debug.class.php index 46c8a8d4..de5c9435 100644 --- a/public/include/classes/debug.class.php +++ b/public/include/classes/debug.class.php @@ -108,5 +108,5 @@ class Debug { } // Instantiate this class -$debug = new Debug(DEBUG); +$debug = new Debug($config['DEBUG']); ?> diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index b71119ac..138cb6dc 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -861,7 +861,7 @@ public function isAuthenticated($logout=true) { $user = new User(); $user->setDebug($debug); $user->setMysql($mysqli); -$user->setSalt(SALT); +$user->setSalt($config['SALT']); $user->setSmarty($smarty); $user->setConfig($config); $user->setMail($mail); diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 83c35b62..44efc690 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -19,14 +19,9 @@ $config['skip_config_tests'] = false; * Debug setting and salts for hashing passwords * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-defines--salts */ -define('DEBUG', 0); -define('SALT', 'PLEASEMAKEMESOMETHINGRANDOM'); -define('SALTY', 'THISSHOULDALSOBERRAANNDDOOM'); - -define('INCLUDE_DIR', BASEPATH . 'include'); -define('CLASS_DIR', INCLUDE_DIR . '/classes'); -define('PAGES_DIR', INCLUDE_DIR . '/pages'); -define('THEME_DIR', BASEPATH . 'templates'); +$config['DEBUG'] = 0; +$config['SALT'] = 'PLEASEMAKEMESOMETHINGRANDOM'; +$config['SALTY'] = 'THISSHOULDALSOBERRAANNDDOOM'; /** * Coin Algorithm diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php index bb658cd1..b18e5bb4 100644 --- a/public/include/smarty_globals.inc.php +++ b/public/include/smarty_globals.inc.php @@ -170,7 +170,7 @@ if ($motd = $setting->getValue('system_motd')) $_SESSION['POPUP'][] = array('CONTENT' => $motd, 'TYPE' => 'info'); // So we can display additional info -$smarty->assign('DEBUG', DEBUG); +$smarty->assign('DEBUG', $config['DEBUG']); // Make it available in Smarty $smarty->assign('PATH', 'site_assets/' . THEME); diff --git a/public/index.php b/public/index.php index fbcc0bcb..40a313b9 100644 --- a/public/index.php +++ b/public/index.php @@ -32,28 +32,16 @@ if (SECHASH_CHECK) { function cfip() { return (@defined('SECURITY')) ? 1 : 0; } } -// Used for performance calculations -$dStartTime = microtime(true); - // This should be okay // No but Its now, - Aim define("BASEPATH", dirname(__FILE__) . "/"); -// Include our configuration (holding defines for the requires) -if (!include_once(BASEPATH . 'include/config/global.inc.php')) die('Unable to load site configuration'); -if (!include_once(BASEPATH . 'include/config/security.inc.dist.php')) die('Unable to load security configuration'); -if (@file_exists(BASEPATH . 'include/config/security.inc.php')) include_once(BASEPATH . 'include/config/security.inc.php'); +// all our includes and config etc are now in bootstrap +include_once('include/bootstrap.php'); // switch to https if config option is enabled $hts = ($config['strict__https_only'] && (!empty($_SERVER['QUERY_STRING']))) ? "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']."?".$_SERVER['QUERY_STRING'] : "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']; -($config['strict__https_only'] && @!$_SERVER['HTTPS']) ? exit(header($hts)):0; - -// Our default template to load, pages can overwrite this later -$master_template = 'master.tpl'; - -// Load Classes, they name defines the $ variable used -// We include all needed files here, even though our templates could load them themself -require_once(INCLUDE_DIR . '/autoloader.inc.php'); +($config['strict__https_only'] && @!$_SERVER['HTTPS']) ? exit(header("Location: ".$hts)):0; if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $config['strict'])) { if (PHP_OS == 'WINNT') { diff --git a/tests/unit/config/SampleTest.php b/tests/unit/config/SampleTest.php index 3ee6c140..ae788a29 100644 --- a/tests/unit/config/SampleTest.php +++ b/tests/unit/config/SampleTest.php @@ -8,8 +8,8 @@ class TestDistConfig extends PHPUnit_Framework_Testcase { * Test to make sure SALT is sane */ function testSaltLength() { - $this->assertNotEmpty(SALT); - $this->assertGreaterThan(1, strlen(SALT)); + $this->assertNotEmpty($config['SALT']); + $this->assertGreaterThan(1, strlen($config['SALTY'])); } } From f298c60260bc2bea9d8ac515b880fa2742aec9c5 Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 09:16:03 -0500 Subject: [PATCH 21/30] little more cleanup put version check/config check after sessions/rate limiter so it works correctly & only uses 1 db hit --- public/include/admin_checks.php | 4 ++-- public/include/autoloader.inc.php | 7 ------- public/include/config/global.inc.dist.php | 1 - public/include/config/security.inc.dist.php | 2 +- public/include/version.inc.php | 9 +++------ public/index.php | 13 ++++++++----- 6 files changed, 14 insertions(+), 22 deletions(-) diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index d1c099cd..7522c6c4 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -104,9 +104,9 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ // salts too short -> notice, salts default -> error if ((strlen($config['SALT']) < 24) || (strlen($config['SALTY']) < 24) || $config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { if ($config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { - $error[] = "You absolutely SHOULD NOT leave your SALT or SALTY default"; + $error[] = "You absolutely SHOULD NOT leave your SALT or SALTY default changing them will require registering again"; } else { - $notice[] = "SALT or SALTY is too short, they should be more than 24 characters and changing them will require registering again."; + $notice[] = "SALT or SALTY is too short, they should be more than 24 characters and changing them will require registering again"; } } diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index f2df9ae4..7a12442c 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -68,11 +68,4 @@ require_once(CLASS_DIR . '/api.class.php'); require_once(INCLUDE_DIR . '/lib/Michelf/Markdown.php'); require_once(INCLUDE_DIR . '/lib/scrypt.php'); -// Include our versions -require_once(INCLUDE_DIR . '/version.inc.php'); - -if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA']['id'])) { - include_once(INCLUDE_DIR . '/admin_checks.inc.php'); -} - ?> diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 44efc690..a06e3e5c 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -13,7 +13,6 @@ $config['version'] = '0.0.7'; */ $config['skip_config_tests'] = false; - /** * Defines * Debug setting and salts for hashing passwords diff --git a/public/include/config/security.inc.dist.php b/public/include/config/security.inc.dist.php index 6856e601..56cd4e32 100644 --- a/public/include/config/security.inc.dist.php +++ b/public/include/config/security.inc.dist.php @@ -53,7 +53,7 @@ $config['twofactor']['options']['changepw'] = true; /** * Lock account after X - * Lock accounts after X attempts + * Lock accounts after X invalid logins or pins * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-lock-accounts-after-failed-logins **/ $config['maxfailed']['login'] = 3; diff --git a/public/include/version.inc.php b/public/include/version.inc.php index d1db6f62..c6204c76 100644 --- a/public/include/version.inc.php +++ b/public/include/version.inc.php @@ -9,12 +9,9 @@ define('CONFIG_VERSION', '0.0.7'); $db_version = $setting->getValue('DB_VERSION'); if ($db_version != DB_VERSION) { // Notify admins via error popup - if (isset($_SESSION['USERDATA']) && $user->isAdmin($_SESSION['USERDATA']['id'])) - $_SESSION['POPUP'][] = array('CONTENT' => 'Database version mismatch (Installed: ' . $db_version . ', Current: ' . DB_VERSION . '). Database update required, please import any new SQL files. Cronjobs have been halted.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Database version mismatch (Installed: ' . $db_version . ', Current: ' . DB_VERSION . '). Database update required, please import any new SQL files. Cronjobs have been halted.', 'TYPE' => 'errormsg'); } - -if (@$config['version'] != CONFIG_VERSION) { +if (@$config['version'] !== CONFIG_VERSION) { // Notify admins via error popup - if (isset($_SESSION['USERDATA']) && $user->isAdmin($_SESSION['USERDATA']['id'])) - $_SESSION['POPUP'][] = array('CONTENT' => 'Configuration file version mismatch (Installed: ' . @$config['version'] . ', Current: ' . CONFIG_VERSION . '). Configuration update required, please check dist config for changes. Cronjobs have been halted.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Configuration file version mismatch (Installed: ' . @$config['version'] . ', Current: ' . CONFIG_VERSION . '). Configuration update required, please check dist config for changes. Cronjobs have been halted.', 'TYPE' => 'errormsg'); } diff --git a/public/index.php b/public/index.php index 40a313b9..f7ebd91a 100644 --- a/public/index.php +++ b/public/index.php @@ -72,7 +72,6 @@ if ($config['memcache']['enabled'] && $config['strict']) { } @setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); } - // Rate limiting if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $config['strict'])) { $skip_check = false; @@ -116,7 +115,8 @@ if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $conf } } -// Got past rate limiter and session manager, show last logged in popup if it's still set +// Got past rate limiter and session manager +// show last logged in popup if it's still set if (@$_GET['clp'] == 1 && @$_SESSION['last_ip_pop']) unset($_SESSION['last_ip_pop']); if (count(@$_SESSION['last_ip_pop']) == 2) { $data = $_SESSION['last_ip_pop']; @@ -130,9 +130,12 @@ if (count(@$_SESSION['last_ip_pop']) == 2) { } } -// Quick config check -if (@$_SESSION['USERDATA']['is_admin'] && !@$config['skip_config_tests']) { - require_once(INCLUDE_DIR. '/admin_checks.php'); +// version check and config check if not disabled +if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA']['id'])) { + require_once(INCLUDE_DIR . '/version.inc.php'); + if (!@$config['skip_config_checks']) { + require_once(INCLUDE_DIR . '/admin_checks.php'); + } } // Create our pages array from existing files From c36413d70c72fe36de2f717995b46c908a135dfd Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 09:17:58 -0500 Subject: [PATCH 22/30] tests not checks --- public/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/index.php b/public/index.php index f7ebd91a..5fcb7ac6 100644 --- a/public/index.php +++ b/public/index.php @@ -133,7 +133,7 @@ if (count(@$_SESSION['last_ip_pop']) == 2) { // version check and config check if not disabled if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA']['id'])) { require_once(INCLUDE_DIR . '/version.inc.php'); - if (!@$config['skip_config_checks']) { + if (!@$config['skip_config_tests']) { require_once(INCLUDE_DIR . '/admin_checks.php'); } } From ae47437ab709d0091c8aaa2d19c54346171f8a7b Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 09:41:50 -0500 Subject: [PATCH 23/30] fixed worker delete csrf thing I stubbed earlier took to field out of the rest of the login forms --- public/include/pages/account/workers.inc.php | 10 +++------- public/templates/mobile/login/default.tpl | 1 - public/templates/mpos/login/small.tpl | 1 - 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php index 7403e0fa..b861600d 100644 --- a/public/include/pages/account/workers.inc.php +++ b/public/include/pages/account/workers.inc.php @@ -4,14 +4,10 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($user->isAuthenticated()) { switch (@$_REQUEST['do']) { case 'delete': - if (!$config['csrf']['enabled'] || ($config['csrf']['enabled'])) { - if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed', 'TYPE' => 'success'); - } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg'); - } + if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed', 'TYPE' => 'success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg'); } break; diff --git a/public/templates/mobile/login/default.tpl b/public/templates/mobile/login/default.tpl index 42df1902..d179f023 100644 --- a/public/templates/mobile/login/default.tpl +++ b/public/templates/mobile/login/default.tpl @@ -1,5 +1,4 @@ -

diff --git a/public/templates/mpos/login/small.tpl b/public/templates/mpos/login/small.tpl index 7ed9b55c..32b61fe5 100644 --- a/public/templates/mpos/login/small.tpl +++ b/public/templates/mpos/login/small.tpl @@ -3,7 +3,6 @@ - From 5d017f60c39c7e3a3e6bb618a0bef6328cebbf39 Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 13:28:38 -0500 Subject: [PATCH 24/30] how this worked before is beyond me --- public/include/classes/user.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 138cb6dc..8e4c0e70 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -814,7 +814,7 @@ class User extends Base { **/ public function isAuthenticated($logout=true) { $this->debug->append("STA " . __METHOD__, 4); - if (@$_SESSION['AUTHENTICATED'] == true && + if (@$_SESSION['AUTHENTICATED'] == '1' && !$this->isLocked($_SESSION['USERDATA']['id']) && $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'] ) return true; From 51818421d80cf051c19bcca8414cf2ddae2f5db8 Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 14:46:21 -0500 Subject: [PATCH 25/30] weird problem, strict for isAuthenticated --- public/include/classes/user.class.php | 13 ++++++++++--- public/include/pages/account/edit.inc.php | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 8e4c0e70..bcac801c 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -814,10 +814,17 @@ class User extends Base { **/ public function isAuthenticated($logout=true) { $this->debug->append("STA " . __METHOD__, 4); - if (@$_SESSION['AUTHENTICATED'] == '1' && - !$this->isLocked($_SESSION['USERDATA']['id']) && - $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'] + if (!$this->config['strict']) { + if (@$_SESSION['AUTHENTICATED'] == true && + !$this->isLocked($_SESSION['USERDATA']['id']) && + $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'] ) return true; + } else { + if (@$_SESSION['AUTHENTICATED'] && $_SESSION['AUTHENTICATED'] == '1' && + (!$this->isLocked($_SESSION['USERDATA']['id'])) && + ($this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'])) + return true; + } // Catchall if ($logout == true) $this->logoutUser($_SERVER['REQUEST_URI']); return false; diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php index 87a9ff3d..6c728c0a 100644 --- a/public/include/pages/account/edit.inc.php +++ b/public/include/pages/account/edit.inc.php @@ -150,7 +150,7 @@ if ($user->isAuthenticated()) { // 2fa - one last time so we can sync with changes we made during this page -if ($user->isAuthenticated() && $config['twofactor']['enabled']) { +if ($config['twofactor']['enabled'] && $user->isAuthenticated()) { // set the token to be the old token, just in case an error occured $ea_token = (@$oldtoken_ea !== '') ? $oldtoken_ea : @$ea_token; $wf_token = (@$oldtoken_wf !== '') ? $oldtoken_wf : @$wf_token; From 53a8b4adf187de64712e3e8aa3345fac2dfb0912 Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 15:43:09 -0500 Subject: [PATCH 26/30] .htaccess check for @ahmedbodi --- public/include/admin_checks.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 7522c6c4..62c9a1f0 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -37,6 +37,11 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ $notice[] = "Memcache is disabled; Almost every linux distro has packages for it, you should be using it if you can."; } } + // check if htaccess exists + if (!file_exists(BASEPATH.".htaccess")) { + $htaccess_link = ".htaccess>"; + $notice[] = "You don't seem to have a .htaccess in your public folder, if you're using apache set it up $htaccess_link"; + } // check if we can write templates/cache and templates/compile -> error if (!is_writable(THEME_DIR.'/cache')) { $error[] = "templates/cache folder is not writable for uid {$apache_user['name']}"; From 0643cf4b877f11fb8b2345394c372ccb49dc66de Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 18:33:34 -0500 Subject: [PATCH 27/30] fixed crons, tested on 2 boxes --- cronjobs/shared.inc.php | 11 ++++++----- public/include/admin_checks.php | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cronjobs/shared.inc.php b/cronjobs/shared.inc.php index fc0d4c9a..b34026df 100644 --- a/cronjobs/shared.inc.php +++ b/cronjobs/shared.inc.php @@ -47,14 +47,15 @@ $dStartTime = microtime(true); // Our cron name $cron_name = basename($_SERVER['PHP_SELF'], '.php'); -// Our security check -define("SECURITY", 1); - // Include our configuration (holding defines for the requires) +require_once(BASEPATH . 'include/config/global.inc.dist.php'); require_once(BASEPATH . 'include/config/global.inc.php'); -// We include all needed files here, even though our templates could load them themself -require_once(INCLUDE_DIR . '/autoloader.inc.php'); +require_once(BASEPATH . 'include/config/security.inc.dist.php'); +@include_once(BASEPATH . 'include/config/security.inc.php'); + +require_once(BASEPATH . 'include/bootstrap.php'); +require_once(BASEPATH . 'include/version.inc.php'); // Command line switches array_shift($argv); diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 62c9a1f0..29f0a3eb 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -39,7 +39,7 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ } // check if htaccess exists if (!file_exists(BASEPATH.".htaccess")) { - $htaccess_link = ".htaccess>"; + $htaccess_link = ".htaccess"; $notice[] = "You don't seem to have a .htaccess in your public folder, if you're using apache set it up $htaccess_link"; } // check if we can write templates/cache and templates/compile -> error From 3d414e9ffa6a381c452862dfa6b9254b614368aa Mon Sep 17 00:00:00 2001 From: xisi Date: Wed, 29 Jan 2014 23:35:07 -0500 Subject: [PATCH 28/30] I think this is a good midway between hardcoding it in and allowing configurability --- public/include/config/global.inc.dist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index a06e3e5c..9a7c45eb 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -219,7 +219,7 @@ $config['pps']['blockavg']['blockcount'] = 10; $config['memcache']['enabled'] = true; $config['memcache']['host'] = 'localhost'; $config['memcache']['port'] = 11211; -$config['memcache']['keyprefix'] = 'mpos_'; +$config['memcache']['keyprefix'] = 'mpos_'.$config['currency'].'_'; $config['memcache']['expiration'] = 90; $config['memcache']['splay'] = 15; From 8487a8d462dc89550089880e65a48a9e70baaf8b Mon Sep 17 00:00:00 2001 From: xisi Date: Thu, 30 Jan 2014 09:38:41 -0500 Subject: [PATCH 29/30] respect client validation settings for failures --- public/include/classes/strict.class.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/include/classes/strict.class.php b/public/include/classes/strict.class.php index 9a535c54..bb6d2974 100644 --- a/public/include/classes/strict.class.php +++ b/public/include/classes/strict.class.php @@ -50,12 +50,12 @@ class strict_session { } public function verify_client($client_model, $data, $login=false) { $fails = 0; - $fails += ((count($client_model)) !== (count($data))) ? 1 : 0; - $fails += ($client_model['ua'] !== $data['ua']) ? 1 : 0; - $fails += ($client_model['ip'] !== $data['ip']) ? 1 : 0; + $fails += ((count($client_model)) !== (count($data)) && $this->validate_client) ? 1 : 0; + $fails += ($client_model['ua'] !== $data['ua'] && $this->validate_client && $this->validate_client_ua) ? 1 : 0; + $fails += ($client_model['ip'] !== $data['ip'] && $this->validate_client && $this->validate_client_ip) ? 1 : 0; $now = time(); $this->validation_misses = $fails; - if ($fails > $this->validate_client_num && $login == false) { + if ($fails > $this->validate_client_num && $login == false && $this->validate_client) { // something changed $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; From afdf3abb29b0c3e076aa38900ffde0e9b1c9bb99 Mon Sep 17 00:00:00 2001 From: xisi Date: Thu, 30 Jan 2014 18:41:56 -0500 Subject: [PATCH 30/30] ripped out all the memcache session stuff, not worth it with the side effects of caching things cleaned up config/checks --- public/include/admin_checks.php | 8 +- public/include/autoloader.inc.php | 2 +- public/include/classes/memcache_ad.class.php | 85 ++++-------- public/include/classes/strict.class.php | 137 ------------------- public/include/classes/user.class.php | 30 ++-- public/include/config/security.inc.dist.php | 20 +-- public/include/database.inc.php | 2 +- public/include/pages/login.inc.php | 12 +- public/include/pages/logout.inc.php | 13 +- public/index.php | 43 +++--- 10 files changed, 60 insertions(+), 292 deletions(-) diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 29f0a3eb..4935047d 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -78,8 +78,8 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ if (mysqli_connect_errno() || !array_key_exists('client_info', $db_connect)) { $error[] = "Unable to connect to mysql using provided credentials"; } - if (($config['strict'] || $config['mc_antidos']) && !$config['memcache']['enabled']) { - $error[] = "strict or mc_antidos are enabled and memcache is not, memcache is required to use these."; + if ($config['mc_antidos'] && !$config['memcache']['enabled']) { + $error[] = "mc_antidos is enabled and memcache is not, memcache is required to use this"; } // poke stratum using gettingstarted details -> enotice if (substr_count(strtolower(PHP_OS), 'nix') > 0) { @@ -102,10 +102,6 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ } // security checks - // strict not on -> notice - if (!$config['strict']) { - $notice[] = "Strict is disabled - if you have memcache, you should turn this on."; - } // salts too short -> notice, salts default -> error if ((strlen($config['SALT']) < 24) || (strlen($config['SALTY']) < 24) || $config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { if ($config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 7a12442c..6cd887e5 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -12,7 +12,7 @@ if (empty($config['algorithm']) || $config['algorithm'] == 'scrypt') { // Default classes require_once(CLASS_DIR . '/debug.class.php'); require_once(INCLUDE_DIR . '/lib/KLogger.php'); -if ($config['strict']) { +if ($config['mysql_filter']) { require_once(CLASS_DIR . '/strict.class.php'); } require_once(INCLUDE_DIR . '/database.inc.php'); diff --git a/public/include/classes/memcache_ad.class.php b/public/include/classes/memcache_ad.class.php index 25b48cf5..724c57d2 100644 --- a/public/include/classes/memcache_ad.class.php +++ b/public/include/classes/memcache_ad.class.php @@ -7,116 +7,79 @@ class MemcacheAntiDos public $rate_limit_this_request = false; public $rate_limit_api_request = false; public $rate_limit_site_request = false; - public function __construct($config, &$memcache, $userORip, $request='', $mcSettings) { + public function __construct($config, &$memcache, $request='') { $this->cache = $memcache; // set our config options - $per_page = ''; - $flush_sec_api = $config['flush_seconds_api']; - $rate_limit_api = $config['rate_limit_api']; - $flush_sec_site = $config['flush_seconds_site']; - $rate_limit_site = $config['rate_limit_site']; - $ajax_add = $config['ajax_hits_additive']; - unset($config); + $userORip = $_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT']; // prep stuff we need to check this request - $key_md5 = md5($mcSettings['keyprefix'].$userORip); + $key_md5 = $config['memcache']['keyprefix'].md5($userORip); $request_data = $this->cache->get($key_md5); $now = time(); - $max_req_flush = max(array($flush_sec_api,$flush_sec_site)); + $max_req_flush = max(array($config['mc_antidos']['flush_seconds_api'],$config['mc_antidos']['flush_seconds_site'])); // check the request if (is_array($request_data)) { // this request key already exists, update it $request_data['la'] = $now; if ($request == 'api') { $request_data['ha'] += 1; - if ($ajax_add) { + if ($config['mc_antidos']['ajax_hits_additive']) { $request_data['hn'] += 1; } } else { $request_data['hn'] += 1; } // not rate limited yet, update the rest of the object - if (($request_data['hn'] < $rate_limit_site) && ($request_data['ha'] < $rate_limit_api)) { - - if (((($request_data['hnl'] + $flush_sec_site) <= $now) || ($request_data['hal'] + $flush_sec_api) <= $now) || (($request_data['la'] + $max_req_flush) <= $now)) { + if (($request_data['hn'] < $config['mc_antidos']['rate_limit_site']) && ($request_data['ha'] < $config['mc_antidos']['rate_limit_api'])) { + if (((($request_data['hnl'] + $config['mc_antidos']['flush_seconds_site']) <= $now) || ($request_data['hal'] + $config['mc_antidos']['flush_seconds_api']) <= $now) || (($request_data['la'] + $max_req_flush) <= $now)) { // needs to be flushed & updated $new = $this->getRequestBase(); $new['key'] = $key_md5; - $new['sid'] = session_id(); - $new['ua'] = md5($_SERVER['HTTP_USER_AGENT']); - $new['ip'] = $key_md5; $new['la'] = $now; - $new['hal'] = ((($request_data['hal'] + $flush_sec_api) <= $now)) ? $now : 1; - $new['hnl'] = ((($request_data['hnl'] + $flush_sec_site) <= $now)) ? $now : 1; - $this->cache->set($key_md5, $new, $max_req_flush); - $this->rate_limit_api_request = ($request_data['ha'] >= $rate_limit_api) ? true : false; - $this->rate_limit_site_request = ($request_data['hn'] >= $rate_limit_site) ? true : false; - //$this->rate_limit_this_request = false; + $new['hal'] = ((($request_data['hal'] + $config['mc_antidos']['flush_seconds_api']) <= $now)) ? $now : 1; + $new['hnl'] = ((($request_data['hnl'] + $config['mc_antidos']['flush_seconds_site']) <= $now)) ? $now : 1; + $this->cache->set($key_md5, $new, $config['memcache']['expiration']); + $this->rate_limit_api_request = ($request_data['ha'] >= $config['mc_antidos']['rate_limit_api']) ? true : false; + $this->rate_limit_site_request = ($request_data['hn'] >= $config['mc_antidos']['rate_limit_site']) ? true : false; } else { // no flush, just update $new = $this->getRequestBase(); - $new['key'] = $key_md5; - $new['sid'] = session_id(); - $new['ua'] = md5($_SERVER['HTTP_USER_AGENT']); - $new['ip'] = $key_md5; + $new['key'] = $request_data['key']; $new['la'] = time(); $new['ha'] = $request_data['ha']; $new['hal'] = $request_data['hal']; $new['hn'] = $request_data['hn']; $new['hnl'] = $request_data['hnl']; - $this->cache->set($key_md5, $new, $max_req_flush); - //$this->rate_limit_this_request = false; - $this->rate_limit_api_request = ($request_data['ha'] >= $rate_limit_api) ? true : false; - $this->rate_limit_site_request = ($request_data['hn'] >= $rate_limit_site) ? true : false; + $this->cache->set($key_md5, $new, $config['memcache']['expiration']); + $this->rate_limit_api_request = ($request_data['ha'] >= $config['mc_antidos']['rate_limit_api']) ? true : false; + $this->rate_limit_site_request = ($request_data['hn'] >= $config['mc_antidos']['rate_limit_site']) ? true : false; } } else { // too many hits, we should rate limit this - //$this->rate_limit_this_request = true; - $this->rate_limit_api_request = ($request_data['ha'] >= $rate_limit_api) ? true : false; - $this->rate_limit_site_request = ($request_data['hn'] >= $rate_limit_site) ? true : false; + $this->rate_limit_api_request = ($request_data['ha'] >= $config['mc_antidos']['rate_limit_api']) ? true : false; + $this->rate_limit_site_request = ($request_data['hn'] >= $config['mc_antidos']['rate_limit_site']) ? true : false; } } else { // doesn't exist for this request_key, create one $new = $this->getRequestBase(); - $new['key'] = $key_md5; - $new['sid'] = session_id(); - $new['ua'] = md5($_SERVER['HTTP_USER_AGENT']); - $new['ip'] = $key_md5; + $new['key'] = $config['memcache']['keyprefix'].md5($userORip); $new['la'] = time(); if ($request == 'api') { $new['ha'] += 1; - if ($ajax_add) { + if ($config['mc_antidos']['ajax_hits_additive']) { $new['hn'] += 1; } } else { $new['hn'] += 1; } - $this->cache->set($key_md5, $new, $max_req_flush); - $this->rate_limit_this_request = false; + $this->cache->set($key_md5, $new, $config['memcache']['expiration']); + $this->rate_limit_api_request = false; + $this->rate_limit_site_request = false; } } public function getRequestBase() { - $new = array( - 'key' => '', - 'sid' => '', - 'ua' => '', - 'ip' => '', - 'la' => 0, - 'hn' => 0, - 'hnl' => 0, - 'ha' => 0, - 'hal' => 0 - ); + $new = array('key' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); return $new; } - public function rateLimitRequest() { - return $this->rate_limit_this_request; - } - public function rateLimitSite() { - return $this->rate_limit_site_request; - } - public function rateLimitAPI() { - return $this->rate_limit_api_request; - } } ?> \ No newline at end of file diff --git a/public/include/classes/strict.class.php b/public/include/classes/strict.class.php index bb6d2974..26576bd1 100644 --- a/public/include/classes/strict.class.php +++ b/public/include/classes/strict.class.php @@ -1,143 +1,6 @@ memcache->delete($key); - } - private $validation_misses = 0; - private $initial_ua; - public function create_or_update_client($client, $force=false, $login=false) { - $read = $this->memcache->get($client['key']); - // this needs to be available later - $update = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); - $update['sid'] = $client['sid']; - $update['ua'] = md5($this->initial_ua); - $update['ip'] = $client['ip']; - $update['la'] = time(); - $update['key'] = md5($this->memcache_key.$client['ip']); - $validation_misses = 0; - if ($read !== false) { - $read_model = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); - $read_model['sid'] = @$read['sid']; - $read_model['ip'] = @$read['ip']; - $read_model['ua'] = @$read['ua']; - $read_model['la'] = @$read['la']; - $read_model['key'] = md5($this->memcache_key.$read['ip']); - // key already exists, update - if ($this->validate_client) { - if ($this->verify_client($read_model, $update, $login)) { - $update_client = $this->memcache->set($update['key'], $update); - } - } - } else { - $update_client = $this->memcache->set($client['key'], $client); - if ($force && $login) { - $update_client = $this->memcache->set($update['key'], $update); - } - } - } - public function verify_client($client_model, $data, $login=false) { - $fails = 0; - $fails += ((count($client_model)) !== (count($data)) && $this->validate_client) ? 1 : 0; - $fails += ($client_model['ua'] !== $data['ua'] && $this->validate_client && $this->validate_client_ua) ? 1 : 0; - $fails += ($client_model['ip'] !== $data['ip'] && $this->validate_client && $this->validate_client_ip) ? 1 : 0; - $now = time(); - $this->validation_misses = $fails; - if ($fails > $this->validate_client_num && $login == false && $this->validate_client) { - // something changed - $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); - $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; - $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; - $this->session_delete_key($client_model['key']); - $this->session_delete_key($data['key']); - @session_start(); - @session_regenerate_id(true); - $_SESSION = null; - $_SESSION['POPUP'][] = array('CONTENT' => "Session revoked due to a change in your client. You may have a plugin messing with your useragent, or your IP address may have changed.", 'TYPE' => 'warning'); - $location.= '?page=login'; - if (!headers_sent()) exit(header('Location: ' . $location)); - exit(''); - } - return ($fails > 0) ? false : true; - } - public function read_if_client_exists($client_key) { - if ($this->memcache !== null) { - $exists = $this->memcache->get($client_key); - } - return ($exists !== null) ? $exists : false; - } - public function regen_session_id() { - $sidbefore = @session_id(); - @session_regenerate_id(true); - $sid = session_id(); - return $sid; - } - public function __construct($config, &$memcache) { - $this->initial_ua = $_SERVER['HTTP_USER_AGENT']; - $this->memcache = $memcache; - $this->memcache_key = $config['memcache']['keyprefix']; - if ($config['strict__verify_client']) { - $this->validate_client = true; - $this->validate_client_ip = $config['strict__verify_client_ip']; - $this->validate_client_ua = $config['strict__verify_client_useragent']; - $this->validate_client_sid = $config['strict__verify_client_sessionid']; - $this->validate_client_num = 0; - if ($config['strict__verify_server']) { - $proto = (@$_SERVER['HTTPS'] == "on") ? 'https' : 'http'; - $location = $proto."://".$_SERVER['SERVER_NAME'] . $_SERVER['SERVER_PORT']; - if ($config['strict__verify_server']) { - if ($config['strict__bind_protocol']."://".$config['strict__bind_host'].$config['strict__bind_port'] !== $location) { - return false; - } - } - } - $client = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); - $client['ua'] = md5($_SERVER['HTTP_USER_AGENT']); - $client['ip'] = md5($_SERVER['REMOTE_ADDR']); - $client['la'] = time(); - $client['key'] = md5($this->memcache_key.$client['ip']); - $read = $this->read_if_client_exists($client['key']); - } - session_set_cookie_params((time()+$config['cookie']['duration']), $config['cookie']['path'], $config['cookie']['domain'], false, true); - $session_start = @session_start(); - $client['sid'] = session_id(); - $valid_session_id = $this->valid_session_id($client['sid']); - if (!$valid_session_id || !$session_start) { - @session_destroy(); - $client['sid'] = $this->regen_session_id(); - session_start(); - } - if ($read !== null) { - // client exists, verify - $this->create_or_update_client($client, true, false); - - } else { - // doesn't exist - $this->create_or_update_client($client, true, true); - } - @setcookie(session_name(), $client['sid'], (time()+$config['cookie']['duration']), $config['cookie']['path'], $config['cookie']['domain'], false, true); - // post changes validate - if ($this->validate_client) { - $read_post = $this->read_if_client_exists($client['key']); - if ($read_post !== null) { - $this->verify_client($client, $read_post, true); - } - } - } -} - class mysqli_strict extends mysqli { public function bind_param($paramTypes) { if (!is_string($paramTypes)) { diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index bcac801c..aa2b0319 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -503,17 +503,10 @@ class User extends Base { if (!empty($lastIP) && (!empty($lastLoginTime))) { $_SESSION['last_ip_pop'] = array($lastIP, $lastLoginTime); } - if ($this->config['strict'] && $this->config['memcache']['enabled']) { - session_regenerate_id(true); - $_SESSION['AUTHENTICATED'] = '1'; - // $this->user from checkUserPassword - $_SESSION['USERDATA'] = $this->user; - } else { - session_regenerate_id(true); - $_SESSION['AUTHENTICATED'] = '1'; - // $this->user from checkUserPassword - $_SESSION['USERDATA'] = $this->user; - } + session_regenerate_id(true); + $_SESSION['AUTHENTICATED'] = '1'; + // $this->user from checkUserPassword + $_SESSION['USERDATA'] = $this->user; } /** @@ -814,17 +807,10 @@ class User extends Base { **/ public function isAuthenticated($logout=true) { $this->debug->append("STA " . __METHOD__, 4); - if (!$this->config['strict']) { - if (@$_SESSION['AUTHENTICATED'] == true && - !$this->isLocked($_SESSION['USERDATA']['id']) && - $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'] - ) return true; - } else { - if (@$_SESSION['AUTHENTICATED'] && $_SESSION['AUTHENTICATED'] == '1' && - (!$this->isLocked($_SESSION['USERDATA']['id'])) && - ($this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'])) - return true; - } + if (@$_SESSION['AUTHENTICATED'] == true && + !$this->isLocked($_SESSION['USERDATA']['id']) && + $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'] + ) return true; // Catchall if ($logout == true) $this->logoutUser($_SERVER['REQUEST_URI']); return false; diff --git a/public/include/config/security.inc.dist.php b/public/include/config/security.inc.dist.php index 56cd4e32..20f4c140 100644 --- a/public/include/config/security.inc.dist.php +++ b/public/include/config/security.inc.dist.php @@ -2,22 +2,12 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; /** - * Strict Mode - * Extra security options that can help protect against a few different types of attacks - * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-strict-mode + * Misc + * Extra security settings + * **/ -$config['strict'] = true; -$config['strict__https_only'] = false; -$config['strict__mysql_filter'] = true; -$config['strict__verify_client'] = true; -$config['strict__verify_client_ip'] = true; -$config['strict__verify_client_useragent'] = true; -$config['strict__verify_client_sessionid'] = true; -$config['strict__verify_client_fails'] = 0; -$config['strict__verify_server'] = false; -$config['strict__bind_protocol'] = 'https'; -$config['strict__bind_host'] = ''; -$config['strict__bind_port'] = 443; +$config['https_only'] = false; +$config['mysql_filter'] = true; /** * Memcache Rate Limiting diff --git a/public/include/database.inc.php b/public/include/database.inc.php index 1146e239..a65e708b 100644 --- a/public/include/database.inc.php +++ b/public/include/database.inc.php @@ -2,7 +2,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // Instantiate class, we are using mysqlng -if ($config['strict'] && $config['strict__mysql_filter']) { +if ($config['mysql_filter']) { $mysqli = new mysqli_strict($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); } else { $mysqli = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); diff --git a/public/include/pages/login.inc.php b/public/include/pages/login.inc.php index d80dd08c..a8f7cd0e 100644 --- a/public/include/pages/login.inc.php +++ b/public/include/pages/login.inc.php @@ -29,17 +29,7 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; - if ($config['strict'] && $config['memcache']['enabled']) { - $update = array('key' => '','sid' => '','ua' => '','ip' => '','la' => 0,'hn' => 0,'hnl' => 0,'ha' => 0,'hal' => 0); - $session->regen_session_id(); - $update['sid'] = session_id(); - $update['ua'] = md5($_SERVER['HTTP_USER_AGENT']); - $update['ip'] = md5($_SERVER['REMOTE_ADDR']); - $update['la'] = time(); - $update['key'] = md5($update['ip']); - $session->create_or_update_client($update, true, true); - $location.= '?page=dashboard'; - } + $location.= '?page=dashboard'; if (!headers_sent()) header('Location: ' . $location); exit(''); } else { diff --git a/public/include/pages/logout.inc.php b/public/include/pages/logout.inc.php index c15f350a..9b6e12a6 100644 --- a/public/include/pages/logout.inc.php +++ b/public/include/pages/logout.inc.php @@ -1,18 +1,7 @@ logoutUser(); - $update = $session::$client_model; - $update['sid'] = session_id(); - $update['ua'] = $_SERVER['HTTP_USER_AGENT']; - $update['ip'] = $_SERVER['REMOTE_ADDR']; - $update['la'] = time(); - $update['key'] = md5($update['ua'].$update['ip']); - $session->create_or_update_client($update, true); -} else { - $user->logoutUser(); -} +$user->logoutUser(); $smarty->assign("CONTENT", "default.tpl"); ?> diff --git a/public/index.php b/public/index.php index 5fcb7ac6..811b9b05 100644 --- a/public/index.php +++ b/public/index.php @@ -40,40 +40,33 @@ define("BASEPATH", dirname(__FILE__) . "/"); include_once('include/bootstrap.php'); // switch to https if config option is enabled -$hts = ($config['strict__https_only'] && (!empty($_SERVER['QUERY_STRING']))) ? "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']."?".$_SERVER['QUERY_STRING'] : "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']; -($config['strict__https_only'] && @!$_SERVER['HTTPS']) ? exit(header("Location: ".$hts)):0; +$hts = ($config['https_only'] && (!empty($_SERVER['QUERY_STRING']))) ? "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']."?".$_SERVER['QUERY_STRING'] : "https://".$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME']; +($config['https_only'] && @!$_SERVER['HTTPS']) ? exit(header("Location: ".$hts)):0; -if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $config['strict'])) { +if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled']) { if (PHP_OS == 'WINNT') { require_once(CLASS_DIR . 'memcached.class.php'); } - // strict mode and memcache antidos need a memcache handle + // memcache antidos needs a memcache handle $memcache = new Memcached(); $memcache->addServer($config['memcache']['host'], $config['memcache']['port']); } -if ($config['memcache']['enabled'] && $config['strict'] || $config['mc_antidos']['enabled']) { +if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled']) { require_once(CLASS_DIR . '/memcache_ad.class.php'); } -if ($config['memcache']['enabled'] && $config['strict']) { - $session = new strict_session($config, $memcache); - if ($config['strict__verify_server'] && !$session) { - // server not verified, session manager will kill the client verification failures - exit(header('HTTP/1.1 401 Unauthorized')); - } -} else { - $session_start = @session_start(); - session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); - if (!$session_start) { - session_destroy(); - session_regenerate_id(true); - session_start(); - } - @setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); +$session_start = @session_start(); +session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); +if (!$session_start) { + session_destroy(); + session_regenerate_id(true); + session_start(); } +@setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); + // Rate limiting -if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $config['strict'])) { +if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled']) { $skip_check = false; // if this is an api call we need to be careful not to time them out for those calls separately $per_page = ''; @@ -97,14 +90,12 @@ if ($config['memcache']['enabled'] && ($config['mc_antidos']['enabled'] || $conf $skip_check = true; } if (!$skip_check) { - $mcad = new MemcacheAntiDos($config['mc_antidos'], $memcache, $_SERVER['REMOTE_ADDR'], $per_page, $config['memcache']); - $rate_limit_reached_site = $mcad->rateLimitSite(); - $rate_limit_reached_api = $mcad->rateLimitAPI(); - if ($rate_limit_reached_api && $is_ajax_call && $config['mc_antidos']['protect_ajax']) { + $mcad = new MemcacheAntiDos($config, $memcache, $per_page); + if ($config['mc_antidos']['protect_ajax'] && $is_ajax_call && $mcad->rate_limit_api_request) { exit(header('HTTP/1.1 401 Unauthorized')); } $error_page = $config['mc_antidos']['error_push_page']; - if ($rate_limit_reached_site == true) { + if ($mcad->rate_limit_site_request) { if (!is_array($error_page) || count($error_page) < 1 || (empty($error_page['page']) && empty($error_page['action']))) { die("You are sending too many requests too fast!"); } else {