I am creating a lgoin time out. I have everything else working perfectly fine on my code. Here is my specification for the timeout:
If a user enters a password wrong 5 times within a 24hr period, lock them out for 48hrs.
If a user enters the password correctly, within the 5 attempts and 24hr period, reset their attempts.
I still need it to time the user out for 48 hours, and display a message letting the user know they have been timed out. If you could help me out with this I'd be really grateful. Here is the code snippet:
Here is a snippet of the code for the login attempt:
if (!$pw_ok) {
if (isset($_SERVER["REMOTE_ADDR"])) {
$str_RemoteHost = $_SERVER["REMOTE_ADDR"];
} else {
$str_RemoteHost = '';
}
$qry_WriteToDatabase = " INSERT INTO cms_user_login_attempts
(
cula_user_id,
cula_date_time,
cula_remote_host,
cula_attempt_count
)
VALUES (
" . $db->SQLString($row->user_id) . ",
Now(),
" . $db->SQLString($str_RemoteHost, true) . ",
'cula_attempt_count'
)";
$db->query($qry_WriteToDatabase);
$qry_UpdateCount = " UPDATE
cms_user_login_attempts
SET
cula_attempt_count = cula_attempt_count + 1
WHERE
cula_user_id = " . $db->SQLString($row->user_id) . " ";
$db->query($qry_UpdateCount);
$qry_CheckDatabase = " SELECT
CASE WHEN count(*) >= 5 THEN 0 ELSE 1 END as allowed_login
FROM
cms_user_login_attempts
WHERE
cula_date_time >= DATE_SUB(CURRENT_TIMESTAMP, interval 48 hour)
AND
cula_user_id = " . $db->SQLString($row->user_id) . "";
$rs_CheckDatabase = $db->query($qry_CheckDatabase);
if (! (isset($qry_CheckDatabase) && $qry_CheckDatabase)) {
$errors->defineError("invalid_user_pass", "Bleh.", array("username","password"));
}
}
edit: I have updated the question and code.
You need to save the login attempt before the password verification
if (! (isset($pw_ok) && $pw_ok))
Therefore, add a boolean field called cula_login_success to indicate if the password verification was successful.
And then query the number of failures in that date, the SQL should be something like this:
$qry="select cula_user_id,count(*) from cms_user_login_attempts where DATEDIFF(cula_date_time,NOW())<=2 and cula_user_id=".$db->SQLString($row->user_id)+" and not exist(select cula_user_id from cms_user_login_attempts where DATEDIFF(cula_date_time,NOW())<=2 and cula_user_id=".$db->SQLString($row->user_id)+" and cula_login_success=1) group by cula_user_id having count(*)>5";
This query should return an empty set, if it doesn't - then it means your user tries to login unsuccessfully more than 5 times, in 2 days, with no successful logins in between
table
--------------------------
user_id | attempts | datetime
Everytime login fails you add one to attempts and update datetime.
When the user logins correctly you update the db and set attempts to zero .
if attemts is equeal or greater than 5 you first check the datetime to see if its greater than 24 hours if so you login and reset attemts else you show a message and dont try to login.
In your table, you should be recording whether the attempt was successful or not. Then, before loading the form again, check if the user has 5 unsuccessful attempts within the last 24 hours and decide whether to lock the account or let the user try again.
DO NOT Do that....
If someone will quess user name, he can easly DDOS the person.
Its better to delay the login. Like - if wrong login count is hight (more than 5 for you) before checking the login use sleep for 10 seconds. This will sloow the atacks but still allow real user to log in.
If there is many failed logins (20-30) then block account for several minutes, and ban ip for hour or so.
That way your users would be able to login, and yet atackers would be blocked.
Related
I have a php file that user can login and logout. I'm currently running on it. I want to show a number when user login.
for example user A login and redirect to userpage.php, I want to show a number like 1,2,3 and still count. I already created this one.
But the problem is when user log out and try to login again, the number is not continue? it become 1,2,3 again.
Is it possible to have a number still counting even when the user logout?
thanks
Update: as you want the numbers to get incremented in background irrespective of login/logout, use cron jobs see this for more info
You have to use counter for each user login which has to be persistent so, save this counter in DB whichever you are using for your application.
Flow would go like:
Check login > Login Succeeded > Fetch current login counter from db
for this specific user > Increment by one > Save it back to DB
General implementation in php would be like (Considering username is always unique)
Note: Below code is not tested
.
.
.
$stmt = $con->prepare("SELECT user_id, username, password, login_count FROM users WHERE username=? AND password=? LIMIT 1");
$stmt->bind_param('ss', $username, $password);
$stmt->execute();
$stmt->bind_result($user_id, $username, $password, $loginCount);
$stmt->store_result();
if($stmt->num_rows == 1) //To check if the row exists
{
if($stmt->fetch()) //fetching the contents of the row
{
$_SESSION['Logged'] = 1;
$_SESSION['user_id'] = $user_id;
$_SESSION['username'] = $username;
$loginCount = $loginCount+1; //increment login counter by 1
//this should be default as 0 when a new user register
//Now save it back to DB using update query
$Updatesql = "UPDATE Table SET loginCount=? WHERE username=?";
$Updatestmt = $con->prepare($Updatesql);
$Updatestmt->bind_param('ds', $loginCount,$username);
$Updatestmt->execute();
if ($Updatestmt->error) {
//Update failed
echo "FAILURE!!! " . $Updatestmt->error;
}
else echo "Updated {$Updatestmt->affected_rows} rows"; //Update succeeded
$Updatestmt->close();
exit();
}
}
else {
echo "INVALID USERNAME/PASSWORD Combination!";
}
$stmt->close();
To achieve this result you cant try logging the login time and logout time and take difference between time and and display the number of seconds have passed since first login.
Step 1: Log the first login time and save it in database.
Step 2: Log the logout time and save it in database.
Step 3: if you want the time elapsed for first login and last logout then calculate the time difference in seconds.
if you want the time elapsed form last login then calculate the time difference between last login and current time.
Step 4: Display the time elapsed on the HTML user page.
I have a site and I want to measure how long a client was connected to my site, one hour or two hour... or? how is it possible?
can someone help me in this regard.
it will be appreciated.
As mentioned in the comments, it's best to use analytic software but if you are looking for something simple (or just learning experience)
<?php
session_start();
if(!isset($_SESSION['sessionId'])) // No session, first time (subject to session timeout)
{
mysqli_query("INSERT INTO visitor_sessions(`started_on`, `last_checkin`) (" . time() . ", " . time() .")");
$_SESSION['sessionId'] = mysqli_insert_id(); // start the 'visiting session'
}
else
{
mysqli_query("UPDATE visitor set `last_checkin` = " . time() . " WHERE id = " .$_SESSION['sessionId']); // Update last checkin
}
?>
visitor_sessions is a table with 3 columns, id, started_on and last_checkin (timestamps).
You can include this script in your pages thus updating last check_in with each new page opened or have jquery call it every x seconds to maintain time even if they just view a page.
PS: Code was not tested but this is the general idea
What is the correct way to let the user verify the captcha after 4 unsuccessfully login attempts within the last 15 minutes. I have got everything running fine but not timestamp part of the query. To be more specific it can display captcha after 4 failed attempts when user try to log in 5th time or so on, irrespective of whether 15min or 30min have passed...
$query1 = "SELECT login_attempts from users WHERE email = '$email' AND last_login < NOW() - INTERVAL 15 MINUTE";
$result1 = mysqli_query($dbc, $query1) OR die(mysqli_error());
$row = mysqli_fetch_array($result1);
$fail = (int)$row['login_attempts'];
If my understanding is correct, You have to check if the 4th last unsuccessful login attempt is before 15 minutes.
For achieving this, you have to store the time-stamps of last four unsuccessful logins in the database.
Create a field called unsuccesful_login_timestamps as text or varchar with large size in your db. We will store the UNIX timestamps of last four unsuccessful logins in comma separated form in this field.
When a user attempts to login, implement the following logic
If username and password is valid, let user login (You can clear the unsuccesful_login_timestamps field if login is succesful if you want). Else, run the following code.
$last_login_string = {{ get unsuccesful_login_timestamps value for this user from database }}
$last_login_string = update_last_login($last_login_string);
$fourth_last_login = get_4th_last_login($last_login_string);
$time_difference = time() - $fourth_last_login;
{{Update unsuccesful_login_timestamps in db with $last_login_string}}
if($time_difference <900){
//show captcha
}else{
//no_need_for_captcha
}
//Method to update last 4 unsuccessful logins by removing
// the last one from the starting and append the latest time in the end
function update_last_login($last_login_string){
$time_array = array();
if(strlen($last_login_string) > 0){
$time_array = explode(",",$last_login_string);
$size = count($time_array);
if($size ==0){ //first attempt
$last_login_string = time();
}else if($size == 4){ //>=4th attempt
$time_array[4]=time();
array_shift($time_array);
$last_login_string = implode(",",$time_array);
}else{ // >0, but <4 attempts
$time_array[$size]=time();
$last_login_string = implode(",",$time_array);
}
return $last_login_string;
}else{
return time();
}
}
function get_4th_last_login($last_login_string){
$time_array = array();
$time_array = explode(",",$last_login_string);
if($size !=4){
$last_login_time time();
}else{
$last_login_time = $time_array[0];
}
return $last_login_time;
}
I'm not terribly familiar with MySQL myself, but DATE_SUB may work:
SELECT login_attempts from users WHERE email = '$email' AND last_login BETWEEN DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND NOW()
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add
EDIT: This answer is assuming that you are storing a timestamp (using time() or $_SERVER['REQUEST_TIME']) as the value of the last_login column in the users table.
What you can do is declare a $time variable using $_SERVER['REQUEST_TIME'] and do something like this:
$time = $_SERVER['REQUEST_TIME'] - 900; // Current time minus 900 seconds (15 minutes)
$query1 = "SELECT login_attempts from users WHERE email = '$email' AND last_login < $time";
If you want to change the time duration, just change the 900 to whatever value (in seconds) you want.
Okay, so my problem is this: when a user has 3 failed login attempts, he/she is supposed to be locked out of his account for an hour based on IP address. The IP address is stored into the table 'login_attempts' along with the fields 'attempts' and 'time'. Here is my code to pull the time and then I add an hour to it because that's when it's supposed to be when the user can try to log in again:
$user_time = new DateTime('20:04:18'); // example time pulled from the db
$add = new DateInterval('PT1H'); // +1 hour
$user->add($add); // should now be 21:04:18
Ok, so now here is the code for the current time. Again, I'm going to make up a time. It's going to be less than an hour so the user should still be LOCKED out:
$now = new DateTime('20:43:22');
if ($now->format('g:i a') < $user_time->format('g:i a')) {
$diff = $user_time->diff($now);
echo 'You still have ' . $diff->format('%i minutes') . ' until you can try again.';
}
else {
// reset login attempts, process login
For some reason this doesn't work properly. What am I doing wrong?
You better have a time field in your database table with int datatype and store the output of time() function for every login attempt. after the nth time unsuccessful attempts the user gets locked and initialize lockout. to check if the lockout time is over, simply compare the output of current time() function with the one stored after the third unsuccessful attempt.
$lockout = 3600;//if one hour
$query_result_for_last_attempt = "some query";
if((time()-$query_result_for_last_attempt) > $lockout){
header(site.php);
}else{
echo "you still need to wait";
}
of course there are beter fantacies you could do with the code!
I think your comparing of the dates is the problem. Try using getTimestamp() instead of format():
$now = new DateTime('20:43:22');
if ($now->getTimestamp() < $user_time->getTimestamp()) {
$diff = $user_time->diff($now);
echo 'You still have ' . $diff->format('%i minutes') . ' until you can try again.';
}
else {
// reset login attempts, process login
I'm new to using php, but here my problem:
I'm working on a website where users can post things to the server.
I'm trying to add a 5 minute limit to how often a user can post. Every time a user posts it updates a field on their row in the database with CURRENT_TIMESTAMP()
What I would like to do is something that checks how long ago they posted and if it is less than 5 minutes ago it disallows them to post yet.
I figure it would look something like this:
<?php
$query = "SELECT * FROM Users_table WHERE Username = '$username'";
$result = mysql_query($query);
if (($result['last_post']-now())<=5minutes) {
echo "Please wait 5 minutes before you can post again.";
} else {
code to let user post
}
?>
The problem i'm having is i don't know how time works very well and don't know how long 5 minutes would look like.
Any help is much appreciated.
Instead of using a database, you can use sessions too:
session_start();
if (isset($_SESSION['last_post']) && $_SESSION['last_post'] + 300 >= time()) {
echo "sorry, please wait for 5 minutes before next post";
} else {
// do your post here
$_SESSION['last_post'] = time();
}
It will add a session variable that keeps track of the last post within this session; every time you post the value gets updated.
When the last time + 5 minutes is in the future, then it hasn't been 5 minutes yet since the last post.
You can check that directly on SQL, then use PHP just to verify if the query returned anything:
$query = "
SELECT * FROM Users_table
WHERE Username = '$username'
AND DATE_ADD(last_post, INTERVAL 5 MINUTE) > NOW()
";
$result = mysql_query($query);
if(mysql_num_rows($result) > 0) {
echo "Please wait 5 minutes before you can post again.";
} else {
//code to let user post
}
SELECT * FROM Users_table WHERE Username = ? AND DATE_ADD(last_post, INTERVAL 5 MINUTE) > NOW()
Then check the result is empty or not.