如何锁定用户帐号一段时间?
How to lock user account for some period of time?
我想知道在登录失败 X 次后锁定用户帐户的最佳方法是什么?我有 table 用于跟踪用户失败的登录尝试。 Table 存储时间戳、用户名、IP 地址和浏览器类型。在我检测到错误的登录信息后,cfquery 会根据用户名或 IP 地址从失败的登录 table 中提取记录。如果有 5 次或更多次无效尝试,我将帐户设置为非活动状态。现在我想以某种方式设置计时器,该计时器将从该用户最后一次无效尝试开始计时 5 分钟。然后帐户应将状态更改为活动。这是我到目前为止的代码:
<cfquery name="checkUser" datasource="#dsn#">
SELECT UserName, Password, Salt, LockedUntil
FROM Users
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
AND Active = 1
</cfquery>
<cfif len(checkUser.LockedUntil) AND dateCompare(now(), checkUser.LockedUntil,'n') EQ -1>
<cfset fnResults.status = "400">
<cfset fnResults.message = "This account is locked for 5 min.">
<cfreturn fnResults>
<cfabort>
</cfif>
<cfset storedPW = checkUser.Password>
<cfset enteredPW = FORM.password & checkUser.Salt>
<cfif checkUser.recordCount NEQ '1' OR (hash(enteredPW,"SHA-512") NEQ storedPW>
<cfquery name="logFail" datasource="#dsn#">
INSERT INTO FailedLogins(
LoginTime,
LoginUN,
LoginIP,
LoginBrowser
)VALUES(
CURRENT_TIMESTAMP,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#FORM.username#" maxlength="50">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#REMOTE_ADDR#" maxlength="20">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#CGI.HTTP_USER_AGENT#" maxlength="500">
)
</cfquery>
<!--- Pull failed logins based on username or IP address. --->
<cfquery name="failedAttempts" datasource="#dsn#">
SELECT LoginTime
FROM FailedLogins
WHERE LoginUN = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
OR LoginIP = <cfqueryparam cfsqltype="cf_sql_varchar" value="#REMOTE_ADDR#" maxlength="20">
</cfquery>
<cfif failedAttempts.recordcount LT 4>
<cfset fnResults.status = "400">
<cfset fnResults.message = "Invalid Username or Password!">
<cfelseif failedAttempts.recordcount EQ 4>
<cfset fnResults.status = "400">
<cfset fnResults.message = "This is your last attempt. If you fail to provide correct information account will be locked!">
<cfelseif failedAttempts.recordcount GTE 5>
<cfset lockUntil = DateAdd('n', 5, now())>
<cfquery name="blockUser" datasource="#dsn#">
UPDATE Users
SET LockedUntil = <cfqueryparam cfsqltype="cf_sql_timestamp" value="#lockUntil#">
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
</cfquery>
<cfset fnResults.status = "400">
<cfset fnResults.message = "This account is locked for 5 min.">
</cfif>
<cfelse>
//Clear failed login attempts
//Update lockedUntil field to NULL
//User logged in authentication successful!
</cfif>
帐户设置为不活动/锁定后,设置倒计时和更改标志状态的最佳方法是什么?我看到有人推荐 SQL Job,但我不确定 job 应该多久 运行 以及如何创建该声明?如果有人可以提供一些示例,请告诉我。谢谢你。
您可以为 checkUser
查询添加一个条件:
<cfquery name="checkUser" datasource="#dsn#">
SELECT UserName, Password, Salt, Active
FROM Users u
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
-- AND Active = 1
AND NOT EXISTS ( SELECT 1 FROM FailedLogins fl
WHERE fl.LoginUN = u.UserName
AND DATEDIFF('ss', fl.LoginTime, CURRENT_TIMESTAMP) >= 300 )
</cfquery>
我相信自 DATEDIFF()
以来 300
秒而不是 5
分钟,我相信 returns 和 int
。如果这不是 SQL 服务器的理想语法(我不经常使用它),我提前道歉。
然后,在上面,如果 Active
为零,您可以(假设密码正确)将其更新为值 1
并删除与该帐户关联的失败登录或以某种方式将它们标记为不活动,这样它们就不再计入 5 次失败的登录。
根据以下评论者的建议编辑的查询:(顺便提一下,这是个好建议!)
<cfquery name="checkUser" datasource="#dsn#">
SELECT UserName, Password, Salt, Active
FROM Users u
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
-- AND Active = 1
AND NOT EXISTS ( SELECT 1 FROM FailedLogins fl
WHERE fl.LoginUN = u.UserName
AND fl.loginTime < DATEADD(second, -300, CURRENT_TIMESTAMP) )
</cfquery>
我认为你的逻辑倒过来会好一些。
不要让列 status
的值为 Active
或 Inactive
,而是考虑让列 locked_until
时间。
最初,新用户的 locked_until 值为 NULL(或 0),表示未锁定。
当连续登录失败时,设置为当前时间+5分钟。
对于该用户的所有操作,检查当前时间是否 > locked_until 值。
如果不是,该帐户仍未激活(锁定)。
编辑:我决定写出一些代码,因为我忘记考虑用户成功登录的情况。请看下面;我不确定原始问题使用的是什么语言,但这个答案是 pseudo-python.
假设我们有一个数据库table类似于以下内容(忽略盐等)
CREATE TABLE Users (
UserName TEXT PRIMARY KEY,
Password TEXT NOT NULL,
LockUntil TIMESTAMP,
FailedLogins INT DEFAULT 0
);
登录检查功能如下。
要点是:
- 成功登录清除将 FailedLogins 设置为 0。
- 锁定帐户时将 FailedLogins 设置为 5(连同 LockUntil)。
- 新的失败登录,其中 FailedLogins=5 是尝试新解锁的帐户。 (即帐户被隐式解锁,用户正在重试)。
def try_login(username, password):
row = execute("SELECT Password,LockUntil,FailedLogins FROM Users WHERE UserName=?", username);
if row is None:
print("Unknown username")
return False
if row.LockUntil is not None and current_time() < row.LockUntil:
print("Account locked. Try again later.")
return False
if password == row.Password:
print('Successful login')
execute("UPDATE Users SET LockUntil=NULL, FailedLogins=0 WHERE UserName=?", username)
return True
if row.FailedLogins == 4:
print("Too many failures; locking account for 5 mins")
lock_until = current_time() + 300
execute("UPDATE Users SET LockUntil=?,FailedLogins=5 WHERE UserName=?", lock_until, username)
return False
failures = row.FailedLogins + 1
if failures == 6:
# User had locked account, which is now unlocked again.
# But they failed to login again, so this is failure 1.
failures = 1
execute("UPDATE Users SET FailedLogins=? WHERE UserName=?", failures, username)
return False
我想知道在登录失败 X 次后锁定用户帐户的最佳方法是什么?我有 table 用于跟踪用户失败的登录尝试。 Table 存储时间戳、用户名、IP 地址和浏览器类型。在我检测到错误的登录信息后,cfquery 会根据用户名或 IP 地址从失败的登录 table 中提取记录。如果有 5 次或更多次无效尝试,我将帐户设置为非活动状态。现在我想以某种方式设置计时器,该计时器将从该用户最后一次无效尝试开始计时 5 分钟。然后帐户应将状态更改为活动。这是我到目前为止的代码:
<cfquery name="checkUser" datasource="#dsn#">
SELECT UserName, Password, Salt, LockedUntil
FROM Users
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
AND Active = 1
</cfquery>
<cfif len(checkUser.LockedUntil) AND dateCompare(now(), checkUser.LockedUntil,'n') EQ -1>
<cfset fnResults.status = "400">
<cfset fnResults.message = "This account is locked for 5 min.">
<cfreturn fnResults>
<cfabort>
</cfif>
<cfset storedPW = checkUser.Password>
<cfset enteredPW = FORM.password & checkUser.Salt>
<cfif checkUser.recordCount NEQ '1' OR (hash(enteredPW,"SHA-512") NEQ storedPW>
<cfquery name="logFail" datasource="#dsn#">
INSERT INTO FailedLogins(
LoginTime,
LoginUN,
LoginIP,
LoginBrowser
)VALUES(
CURRENT_TIMESTAMP,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#FORM.username#" maxlength="50">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#REMOTE_ADDR#" maxlength="20">,
<cfqueryparam cfsqltype="cf_sql_varchar" value="#CGI.HTTP_USER_AGENT#" maxlength="500">
)
</cfquery>
<!--- Pull failed logins based on username or IP address. --->
<cfquery name="failedAttempts" datasource="#dsn#">
SELECT LoginTime
FROM FailedLogins
WHERE LoginUN = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
OR LoginIP = <cfqueryparam cfsqltype="cf_sql_varchar" value="#REMOTE_ADDR#" maxlength="20">
</cfquery>
<cfif failedAttempts.recordcount LT 4>
<cfset fnResults.status = "400">
<cfset fnResults.message = "Invalid Username or Password!">
<cfelseif failedAttempts.recordcount EQ 4>
<cfset fnResults.status = "400">
<cfset fnResults.message = "This is your last attempt. If you fail to provide correct information account will be locked!">
<cfelseif failedAttempts.recordcount GTE 5>
<cfset lockUntil = DateAdd('n', 5, now())>
<cfquery name="blockUser" datasource="#dsn#">
UPDATE Users
SET LockedUntil = <cfqueryparam cfsqltype="cf_sql_timestamp" value="#lockUntil#">
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
</cfquery>
<cfset fnResults.status = "400">
<cfset fnResults.message = "This account is locked for 5 min.">
</cfif>
<cfelse>
//Clear failed login attempts
//Update lockedUntil field to NULL
//User logged in authentication successful!
</cfif>
帐户设置为不活动/锁定后,设置倒计时和更改标志状态的最佳方法是什么?我看到有人推荐 SQL Job,但我不确定 job 应该多久 运行 以及如何创建该声明?如果有人可以提供一些示例,请告诉我。谢谢你。
您可以为 checkUser
查询添加一个条件:
<cfquery name="checkUser" datasource="#dsn#">
SELECT UserName, Password, Salt, Active
FROM Users u
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
-- AND Active = 1
AND NOT EXISTS ( SELECT 1 FROM FailedLogins fl
WHERE fl.LoginUN = u.UserName
AND DATEDIFF('ss', fl.LoginTime, CURRENT_TIMESTAMP) >= 300 )
</cfquery>
我相信自 DATEDIFF()
以来 300
秒而不是 5
分钟,我相信 returns 和 int
。如果这不是 SQL 服务器的理想语法(我不经常使用它),我提前道歉。
然后,在上面,如果 Active
为零,您可以(假设密码正确)将其更新为值 1
并删除与该帐户关联的失败登录或以某种方式将它们标记为不活动,这样它们就不再计入 5 次失败的登录。
根据以下评论者的建议编辑的查询:(顺便提一下,这是个好建议!)
<cfquery name="checkUser" datasource="#dsn#">
SELECT UserName, Password, Salt, Active
FROM Users u
WHERE UserName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#trim(FORM.username)#" maxlength="50">
-- AND Active = 1
AND NOT EXISTS ( SELECT 1 FROM FailedLogins fl
WHERE fl.LoginUN = u.UserName
AND fl.loginTime < DATEADD(second, -300, CURRENT_TIMESTAMP) )
</cfquery>
我认为你的逻辑倒过来会好一些。
不要让列 status
的值为 Active
或 Inactive
,而是考虑让列 locked_until
时间。
最初,新用户的 locked_until 值为 NULL(或 0),表示未锁定。
当连续登录失败时,设置为当前时间+5分钟。
对于该用户的所有操作,检查当前时间是否 > locked_until 值。 如果不是,该帐户仍未激活(锁定)。
编辑:我决定写出一些代码,因为我忘记考虑用户成功登录的情况。请看下面;我不确定原始问题使用的是什么语言,但这个答案是 pseudo-python.
假设我们有一个数据库table类似于以下内容(忽略盐等)
CREATE TABLE Users (
UserName TEXT PRIMARY KEY,
Password TEXT NOT NULL,
LockUntil TIMESTAMP,
FailedLogins INT DEFAULT 0
);
登录检查功能如下。 要点是:
- 成功登录清除将 FailedLogins 设置为 0。
- 锁定帐户时将 FailedLogins 设置为 5(连同 LockUntil)。
- 新的失败登录,其中 FailedLogins=5 是尝试新解锁的帐户。 (即帐户被隐式解锁,用户正在重试)。
def try_login(username, password):
row = execute("SELECT Password,LockUntil,FailedLogins FROM Users WHERE UserName=?", username);
if row is None:
print("Unknown username")
return False
if row.LockUntil is not None and current_time() < row.LockUntil:
print("Account locked. Try again later.")
return False
if password == row.Password:
print('Successful login')
execute("UPDATE Users SET LockUntil=NULL, FailedLogins=0 WHERE UserName=?", username)
return True
if row.FailedLogins == 4:
print("Too many failures; locking account for 5 mins")
lock_until = current_time() + 300
execute("UPDATE Users SET LockUntil=?,FailedLogins=5 WHERE UserName=?", lock_until, username)
return False
failures = row.FailedLogins + 1
if failures == 6:
# User had locked account, which is now unlocked again.
# But they failed to login again, so this is failure 1.
failures = 1
execute("UPDATE Users SET FailedLogins=? WHERE UserName=?", failures, username)
return False