Hi all,

All right, here's what I am trying to achieve but have no idea how to do it:

My site requires users to login and every page is password protected. As part of preventing hacking (to a small extent, though) I am trying to TEMPORARILY disable the user's account after they have made 5 consecutive invalid login attempts. After 10 consecutive attempts, their account is PERMANENTLY disabled and the only way to reactivate the account is by emailing me (or the admin).

I have been able to get the temporary disabling part done, but have no clue how the account can be permanently locked. Could someone help me figure this out?

Thanks!

You would have to test it out, but it seems like you need to track 3 things:

1) the number of consecutive bad logins
2) the date and time of the last bad login
3) a boolean flag indicating whether the user is permanently locked out

When a user attempts to log in, you could retrieve those three fields for supplied user name:

1. If the user does not exist, display an error and abort.
2. Next, check if they are permanently logged out. If yes, display an error and abort
3. Check the current time against the date of temporary lockout. If the date is not null and within 20 minutes, display an error and abort.

If they pass those checks, verify their login information:

1. if the passwrd is valid, reset the bad login information
a) reset bad login count = 0
b) reset last bad login date = NULL

2. Otherwise, update the bad login information
a) increment the bad login count
b) if new login count is = 4, display a message that the next attempt will lock them out for for 20 minutes. Suggest they use your application's "Forgot your password" option.
c) if new login count is = 5, update the temporary lockout date and time.
Display a message that they are locked out for 20 minutes.
c) if the login count >= 10, set the permanent lockout flag to true

HTH

without coding the sql this is a thought process only
create a table in the database temp_bans.
with colums for username logintimestamp failurecount banned

on login {
if temp_bans.username AND banned AND timestamp+20minutes > timenow die( you are banned until ($timestamp+20minutes))
if login fail {
if not temp_bans.username { create temp_bans.username }
update temp_bans.username increment falurecount timestamp
if failurecount=5 {update temp_bans.username (banned=yes failurecount=0)}
}
if login succeeds {delete temp_bans.username}
}
with a little thought this is only a single sql query, not up to thought at the moment

I just got back to this site and implementing the login feature again. There is something I am not doing correct. After 5 unsuccessful login attempts, a trigger in the DB flips the AccountStatus bit from 1 (Active Account) to 0 (Suspended Acct). However, the next time when I try to login using the correct password, I keep getting redirected to the FailedLogin.cfm script.

Below is the code. When I get rid of the <cfswitch><cfcase> lines, it seems to work fine. Anyone able to figure out what's wrong?

<cfif IsDefined(HTMLEditFormat("FORM.j_username"))>
   <cfset MM_redirectLoginSuccess="RedirectLogin.cfm">
   <cfset MM_redirectLoginFailed="FailedLogin.cfm">

   <cfquery name="MM_rsUser" datasource="#request.dsn#">
         SELECT	Username, Password, FirstName, UserType, InvalidLoginAttempts, AccountStatus
         FROM 	dbo.tblLoginData
         WHERE 	Username = <cfqueryparam value="#HTMLEditFormat(FORM.j_username)#" cfsqltype="cf_sql_varchar">
         AND 	Password = <cfqueryparam value="#Hash(FORM.j_password, "SHA-256")#" cfsqltype="cf_sql_varchar">
   </cfquery>

<!--- If user SUCCESSFULLY LOGGED IN, reset previous Invalid Attempts count to ZERO --->
<cfif MM_rsUser.RecordCount NEQ 0>
       <cfswitch expression="#MM_rsUser.AccountStatus#">
	      <cfcase value="1">
		   <cftry>
		        <cflock scope="Session" timeout="30" type="Exclusive">
			       <cfset Session.MM_Username=HTMLEditFormat(FORM.j_username)>
			       <cfset Session.MM_FirstName = MM_rsUser.FirstName>
			        <cfset Session.MM_UserAuthorization=MM_rsUser.UserType[1]>

			       <cfquery name="resetInvalidAttemptsCount" datasource="#request.dsn#">
			            UPDATE		tblLoginData
			             SET			InvalidLoginAttempts = 0,
			                                        AccountStatus = 1,
					         		LastLoginTime = #Now()#
			              WHERE		Username = '#HTMLEditFormat(FORM.j_username)#'
			        </cfquery>
			</cflock>

			<cfif IsDefined("URL.accessdenied") AND false>
				<cfset MM_redirectLoginSuccess=URL.accessdenied>
			</cfif>
			<cflocation url="#MM_redirectLoginSuccess#" addtoken="no">
	
			<cfcatch type="Lock">
			<!--- code for handling timeout of cflock --->
			</cfcatch>
		</cftry>
		</cfcase>
			<cfcase value="0">
				<div id="error">Account Disabled</div>
			</cfcase>
		</cfswitch>
	<cfelse>
		<!--- If UNSUCCESSFUL LOGIN ATTEMPT was made, increment Invalid Attempts count by 1 --->			
		<cfquery name="updateInvalidAttemptsCount" datasource="#request.dsn#">
			UPDATE		tblLoginData
			SET			InvalidLoginAttempts = InvalidLoginAttempts + 1,
			LastInvalidLoginTime = #Now()#
			WHERE		Username = '#HTMLEditFormat(FORM.j_username)#'
		</cfquery>
	</cfif>

	<cflocation url="#MM_redirectLoginFailed#" addtoken="no">

<cfelse>
  	<cfset MM_LoginAction=CGI.SCRIPT_NAME>
 	 <cfif CGI.QUERY_STRING NEQ "">
		<cfset MM_LoginAction=MM_LoginAction & "?" & XMLFormat(CGI.QUERY_STRING)>
  	</cfif>
</cfif>

I keep getting redirected to the FailedLogin.cfm script.

<cfif IsDefined(HTMLEditFormat("FORM.j_username"))>

      <cfif MM_rsUser.RecordCount NEQ 0>
           .....
     <cfelse>
         .....
     </cfif>

      [B]<cflocation url="#MM_redirectLoginFailed#" addtoken="no">[/B]

<cfelse>
.... 
</cfif>

Well ...look at your code. That is exactly what you're telling CF to do ... always redirect to login failed.

Did you actually test this code? Because it doesn't look right ...

Edited 7 Years Ago by arrgh: n/a

This question has already been answered. Start a new discussion instead.