|
@@ -180,7 +180,7 @@ if (isset($_REQUEST['act']) && $_REQUEST['act'] == 'recover') {
|
180
|
180
|
|
181
|
181
|
// Either a form for the user's email address, or a success message
|
182
|
182
|
require('recover_step1.php');
|
183
|
|
- } // End if (step 1)
|
|
183
|
+ }
|
184
|
184
|
|
185
|
185
|
} // End password recovery
|
186
|
186
|
|
|
@@ -189,81 +189,24 @@ else {
|
189
|
189
|
$Validate->SetFields('username', true, 'regex', 'You did not enter a valid username.', array('regex' => USERNAME_REGEX));
|
190
|
190
|
$Validate->SetFields('password', '1', 'string', 'You entered an invalid password.', array('minlength' => '6', 'maxlength' => '307200'));
|
191
|
191
|
|
192
|
|
- $DB->query("
|
193
|
|
- SELECT ID, Attempts, Bans, BannedUntil
|
194
|
|
- FROM login_attempts
|
195
|
|
- WHERE IP = '".db_string($_SERVER['REMOTE_ADDR'])."'");
|
196
|
|
- // Todo: handle IP encryption
|
197
|
|
- list($AttemptID, $Attempts, $Bans, $BannedUntil) = $DB->next_record();
|
|
192
|
+ list($Attempts, $Banned) = $Cache->get_value('login_attempts_'.db_string($_SERVER['REMOTE_ADDR']));
|
198
|
193
|
|
199
|
194
|
// Function to log a user's login attempt
|
200
|
|
- function log_attempt($UserID) {
|
201
|
|
- global $DB, $Cache, $AttemptID, $Attempts, $Bans, $BannedUntil;
|
202
|
|
- if (!apc_exists('DBKEY')) { return; }
|
203
|
|
- $IPStr = $_SERVER['REMOTE_ADDR'];
|
204
|
|
- $IPA = substr($IPStr, 0, strcspn($IPStr, '.'));
|
205
|
|
- $IP = Tools::ip_to_unsigned($IPStr);
|
206
|
|
- if ($AttemptID) { // User has attempted to log in recently
|
207
|
|
- $Attempts++;
|
208
|
|
- if ($Attempts > 5) { // Only 6 allowed login attempts, ban user's IP
|
209
|
|
- $BannedUntil = time_plus(60 * 60 * 6);
|
210
|
|
- $DB->query("
|
211
|
|
- UPDATE login_attempts
|
212
|
|
- SET
|
213
|
|
- LastAttempt = '".sqltime()."',
|
214
|
|
- Attempts = '".db_string($Attempts)."',
|
215
|
|
- BannedUntil = '".db_string($BannedUntil)."',
|
216
|
|
- Bans = Bans + 1
|
217
|
|
- WHERE ID = '".db_string($AttemptID)."'");
|
218
|
|
-
|
219
|
|
- if ($Bans > 9) { // Automated bruteforce prevention
|
220
|
|
- $DB->query("
|
221
|
|
- SELECT Reason
|
222
|
|
- FROM ip_bans
|
223
|
|
- WHERE $IP BETWEEN FromIP AND ToIP");
|
224
|
|
- if ($DB->has_results()) {
|
225
|
|
- //Ban exists already, only add new entry if not for same reason
|
226
|
|
- list($Reason) = $DB->next_record(MYSQLI_BOTH, false);
|
227
|
|
- if ($Reason != 'Automated ban per >60 failed login attempts') {
|
228
|
|
- $DB->query("
|
229
|
|
- UPDATE ip_bans
|
230
|
|
- SET Reason = CONCAT('Automated ban per >60 failed login attempts AND ', Reason)
|
231
|
|
- WHERE FromIP = $IP
|
232
|
|
- AND ToIP = $IP");
|
233
|
|
- }
|
234
|
|
- } else {
|
235
|
|
- //No ban
|
236
|
|
- $DB->query("
|
237
|
|
- INSERT IGNORE INTO ip_bans
|
238
|
|
- (FromIP, ToIP, Reason)
|
239
|
|
- VALUES
|
240
|
|
- ('".$IP."','".$IP."', 'Automated ban per >60 failed login attempts')");
|
241
|
|
- $Cache->delete_value("ip_bans_$IPA");
|
242
|
|
- }
|
243
|
|
- }
|
244
|
|
- } else {
|
245
|
|
- // User has attempted fewer than 6 logins
|
246
|
|
- $DB->query("
|
247
|
|
- UPDATE login_attempts
|
248
|
|
- SET
|
249
|
|
- LastAttempt = '".sqltime()."',
|
250
|
|
- Attempts = '".db_string($Attempts)."',
|
251
|
|
- BannedUntil = '0000-00-00 00:00:00'
|
252
|
|
- WHERE ID = '".db_string($AttemptID)."'");
|
253
|
|
- }
|
254
|
|
- } else { // User has not attempted to log in recently
|
255
|
|
- $Attempts = 1;
|
256
|
|
- $DB->query("
|
257
|
|
- INSERT INTO login_attempts
|
258
|
|
- (UserID, IP, LastAttempt, Attempts)
|
259
|
|
- VALUES
|
260
|
|
- ('".db_string($UserID)."', '".db_string(DBCrypt::encrypt($IPStr))."', '".sqltime()."', 1)");
|
|
195
|
+ function log_attempt() {
|
|
196
|
+ global $DB, $Cache, $Attempts;
|
|
197
|
+ $Attempts = ($Attempts ?? 0) + 1;
|
|
198
|
+ $Cache->cache_value('login_attempts_'.db_string($_SERVER['REMOTE_ADDR']), array($Attempts, ($Attempts > 5)), 60*60*$Attempts);
|
|
199
|
+ $AllAttempts = $Cache->get_value('login_attempts');
|
|
200
|
+ $AllAttempts[$_SERVER['REMOTE_ADDR']] = time()+(60*60*$Attempts);
|
|
201
|
+ foreach($AllAttempts as $IP => $Time) {
|
|
202
|
+ if ($Time < time()) { unset($AllAttempts[$IP]); }
|
261
|
203
|
}
|
262
|
|
- } // end log_attempt function
|
|
204
|
+ $Cache->cache_value('login_attempts', $AllAttempts, 0);
|
|
205
|
+ }
|
263
|
206
|
|
264
|
207
|
// If user has submitted form
|
265
|
208
|
if (isset($_POST['username']) && !empty($_POST['username']) && isset($_POST['password']) && !empty($_POST['password'])) {
|
266
|
|
- if (strtotime($BannedUntil) > time()) {
|
|
209
|
+ if ($Banned) {
|
267
|
210
|
header("Location: login.php");
|
268
|
211
|
die();
|
269
|
212
|
}
|
|
@@ -282,7 +225,7 @@ else {
|
282
|
225
|
WHERE Username = '".db_string($_POST['username'])."'
|
283
|
226
|
AND Username != ''");
|
284
|
227
|
list($UserID, $PermissionID, $CustomPermissions, $PassHash, $Enabled) = $DB->next_record(MYSQLI_NUM, array(2));
|
285
|
|
- if (strtotime($BannedUntil) < time()) {
|
|
228
|
+ if (!$Banned) {
|
286
|
229
|
if ($UserID && Users::check_password($_POST['password'], $PassHash)) {
|
287
|
230
|
// Update hash if better algorithm available
|
288
|
231
|
if (password_needs_rehash($PassHash, PASSWORD_DEFAULT)) {
|
|
@@ -303,7 +246,6 @@ else {
|
303
|
246
|
setcookie('session', $Cookie, 0, '/', '', true, true);
|
304
|
247
|
}
|
305
|
248
|
|
306
|
|
- //TODO: another tracker might enable this for donors, I think it's too stupid to bother adding that
|
307
|
249
|
// Because we <3 our staff
|
308
|
250
|
$Permissions = Permissions::get_permissions($PermissionID);
|
309
|
251
|
$CustomPermissions = unserialize($CustomPermissions);
|
|
@@ -348,7 +290,7 @@ else {
|
348
|
290
|
die();
|
349
|
291
|
}
|
350
|
292
|
} else {
|
351
|
|
- log_attempt($UserID);
|
|
293
|
+ log_attempt();
|
352
|
294
|
if ($Enabled == 2) {
|
353
|
295
|
|
354
|
296
|
// Save the username in a cookie for the disabled page
|
|
@@ -360,19 +302,19 @@ else {
|
360
|
302
|
setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
|
361
|
303
|
}
|
362
|
304
|
} else {
|
363
|
|
- log_attempt($UserID);
|
|
305
|
+ log_attempt();
|
364
|
306
|
|
365
|
307
|
$Err = 'Your username or password was incorrect.';
|
366
|
308
|
setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
|
367
|
309
|
}
|
368
|
310
|
|
369
|
311
|
} else {
|
370
|
|
- log_attempt($UserID);
|
|
312
|
+ log_attempt();
|
371
|
313
|
setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
|
372
|
314
|
}
|
373
|
315
|
|
374
|
316
|
} else {
|
375
|
|
- log_attempt('0');
|
|
317
|
+ log_attempt();
|
376
|
318
|
setcookie('keeplogged', '', time() + 60 * 60 * 24 * 365, '/', '', false);
|
377
|
319
|
}
|
378
|
320
|
}
|