Merge pull request #320 from wrongecho/brute-force-login
Add basic IP login brute force protection
This commit is contained in:
@@ -29,16 +29,38 @@ if(isset($_POST['login'])){
|
||||
// Sessions should start after the user has POSTed data
|
||||
session_start();
|
||||
|
||||
$email = strip_tags(mysqli_real_escape_string($mysqli,$_POST['email']));
|
||||
$password = $_POST['password'];
|
||||
$current_code = strip_tags(mysqli_real_escape_string($mysqli,$_POST['current_code']));
|
||||
if(!empty($current_code)){
|
||||
$current_code = strip_tags(mysqli_real_escape_string($mysqli,$_POST['current_code']));
|
||||
}
|
||||
$sql = mysqli_query($mysqli,"SELECT * FROM users WHERE user_email = '$email'");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
// Check recent failed login attempts for this IP (more than 10 failed logins in 5 mins)
|
||||
|
||||
if(password_verify($password, $row['user_password'])){
|
||||
// TODO: We can probably just use a count for this, but couldn't make it not count *everything*
|
||||
$ip_failed_logins_sql = mysqli_query($mysqli, "SELECT * FROM logs WHERE log_ip = '$ip' AND log_type = 'Login' AND log_action = 'Failed' AND log_created_at > (NOW() - INTERVAL 5 MINUTE)");
|
||||
$failed_login_count = mysqli_num_rows($ip_failed_logins_sql);
|
||||
|
||||
// Login brute force check
|
||||
if($failed_login_count >= 10){
|
||||
|
||||
// Logging
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Failed', log_description = 'Failed login attempt due to IP lockout', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW()");
|
||||
|
||||
// Send an alert only count hits 10 to reduce flooding alerts (using 1 as "default" company)
|
||||
if($failed_login_count == 10){
|
||||
mysqli_query($mysqli,"INSERT INTO alerts SET alert_type = 'Lockout', alert_message = '$ip was locked out for repeated failed login attempts.', alert_date = NOW(), company_id = '1'");
|
||||
}
|
||||
|
||||
// Inform user
|
||||
$response = '<div class=\'alert alert-danger\'>IP Lockout - Please try again later.<button class=\'close\' data-dismiss=\'alert\'>×</button></div>';
|
||||
}
|
||||
|
||||
// Passed login brute force check
|
||||
else{
|
||||
$email = strip_tags(mysqli_real_escape_string($mysqli, $_POST['email']));
|
||||
$password = $_POST['password'];
|
||||
$current_code = strip_tags(mysqli_real_escape_string($mysqli, $_POST['current_code']));
|
||||
if (!empty($current_code)) {
|
||||
$current_code = strip_tags(mysqli_real_escape_string($mysqli, $_POST['current_code']));
|
||||
}
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM users WHERE user_email = '$email'");
|
||||
$row = mysqli_fetch_array($sql);
|
||||
if (password_verify($password, $row['user_password'])) {
|
||||
|
||||
$token = $row['user_token'];
|
||||
$_SESSION['user_id'] = $row['user_id'];
|
||||
@@ -47,17 +69,17 @@ if(isset($_POST['login'])){
|
||||
$user_id = $row['user_id'];
|
||||
|
||||
// Setup encryption session key
|
||||
if(isset($row['user_specific_encryption_ciphertext'])){
|
||||
if (isset($row['user_specific_encryption_ciphertext'])) {
|
||||
$user_encryption_ciphertext = $row['user_specific_encryption_ciphertext'];
|
||||
$site_encryption_master_key = decryptUserSpecificKey($user_encryption_ciphertext, $password);
|
||||
generateUserSessionKey($site_encryption_master_key);
|
||||
}
|
||||
|
||||
// Setup extension
|
||||
if(isset($row['user_extension_key']) && !empty($row['user_extension_key'])){
|
||||
if (isset($row['user_extension_key']) && !empty($row['user_extension_key'])) {
|
||||
// Extension cookie
|
||||
// Note: Browsers don't accept cookies with SameSite None if they are not HTTPS.
|
||||
setcookie("user_extension_key", "$row[user_extension_key]", ['path' => '/','secure' => true,'httponly' => true,'samesite' => 'None']);
|
||||
setcookie("user_extension_key", "$row[user_extension_key]", ['path' => '/', 'secure' => true, 'httponly' => true, 'samesite' => 'None']);
|
||||
|
||||
// Set PHP session in DB so we can access the session encryption data (above)
|
||||
$user_php_session = session_id();
|
||||
@@ -65,12 +87,12 @@ if(isset($_POST['login'])){
|
||||
|
||||
}
|
||||
|
||||
if(empty($token)){
|
||||
if (empty($token)) {
|
||||
$_SESSION['logged'] = TRUE;
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Login', log_action = 'Success', log_description = '$user_name successfully logged in', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Success', log_description = '$user_name successfully logged in', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
|
||||
|
||||
header("Location: dashboard.php");
|
||||
}else{
|
||||
} else {
|
||||
$token_field = "<div class='input-group mb-3'>
|
||||
<input type='text' class='form-control' placeholder='Token' name='current_code' autofocus>
|
||||
<div class='input-group-append'>
|
||||
@@ -82,13 +104,13 @@ if(isset($_POST['login'])){
|
||||
|
||||
require_once("rfc6238.php");
|
||||
|
||||
if(TokenAuth6238::verify($token,$current_code)){
|
||||
if (TokenAuth6238::verify($token, $current_code)) {
|
||||
$_SESSION['logged'] = TRUE;
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Login 2FA', log_action = 'Success', log_description = '$user_name successfully logged in using 2FA', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login 2FA', log_action = 'Success', log_description = '$user_name successfully logged in using 2FA', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
|
||||
//header("Location: $config_start_page");
|
||||
header("Location: dashboard.php");
|
||||
}else{
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Login', log_action = '2FA Failed', log_description = '$user_name failed 2FA', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
|
||||
} else {
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = '2FA Failed', log_description = '$user_name failed 2FA', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW(), log_user_id = $user_id");
|
||||
|
||||
$response = "
|
||||
<div class='alert alert-primary'>
|
||||
@@ -99,8 +121,8 @@ if(isset($_POST['login'])){
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Login', log_action = 'Failed', log_description = 'Failed login attempt using $email', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW()");
|
||||
} else {
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Login', log_action = 'Failed', log_description = 'Failed login attempt using $email', log_ip = '$ip', log_user_agent = '$user_agent', log_created_at = NOW()");
|
||||
|
||||
$response = "
|
||||
<div class='alert alert-danger'>
|
||||
@@ -109,13 +131,14 @@ if(isset($_POST['login'])){
|
||||
</div>
|
||||
";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title><?php echo $config_app_name; ?> | Login</title>
|
||||
@@ -128,9 +151,9 @@ if(isset($_POST['login'])){
|
||||
<link rel="stylesheet" href="dist/css/adminlte.min.css">
|
||||
<!-- Google Font: Source Sans Pro -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
|
||||
</head>
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box">
|
||||
</head>
|
||||
<body class="hold-transition login-page">
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<b>IT</b>Flow
|
||||
</div>
|
||||
@@ -165,26 +188,26 @@ if(isset($_POST['login'])){
|
||||
</div>
|
||||
<!-- /.login-card-body -->
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.login-box -->
|
||||
</div>
|
||||
<!-- /.login-box -->
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="plugins/jquery/jquery.min.js"></script>
|
||||
<!-- Bootstrap 4 -->
|
||||
<script src="plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="dist/js/adminlte.min.js"></script>
|
||||
<!-- jQuery -->
|
||||
<script src="plugins/jquery/jquery.min.js"></script>
|
||||
<!-- Bootstrap 4 -->
|
||||
<script src="plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- AdminLTE App -->
|
||||
<script src="dist/js/adminlte.min.js"></script>
|
||||
|
||||
<script src="plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
|
||||
<script src="plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
|
||||
|
||||
<!-- Prevents resubmit on refresh or back -->
|
||||
<script>
|
||||
<!-- Prevents resubmit on refresh or back -->
|
||||
<script>
|
||||
|
||||
if(window.history.replaceState){
|
||||
window.history.replaceState(null,null,window.location.href);
|
||||
}
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user