我正在尝试解决此业务问题:
我想在不使用Timer
的情况下执行此操作,并且我将大部分信息存储在Session
public class LoginExp
{
public DateTime FirstAttempt;
public int NumOfAttempts;
}
我将FirstAttempt
日期时间存储在页面加载上。
在“登录”按钮上单击:
NumOfAttempts
FirstAttempt
和DateTime.Now
之间经过的分钟数,并执行5的模式,但这不会告诉我这是哪个时间段(换句话说,用户可能已尝试3从第2分钟开始,然后在第7分钟回来再次尝试。mod
会给我相同的价值。关于我如何做到这一点的任何想法?
答案 0 :(得分:6)
请不要使用计时器。为这些数据和用户数据腾出空间,保存,存储某种形式的凭据。只需保留上次登录尝试时间和尝试次数 - 如果时间大于 n ,则下次尝试将清除之前的计数并从0开始,依此类推。
答案 1 :(得分:2)
您可以存储尝试时间戳列表,并使用它来确定用户是否被锁定。这不是完整的代码,但这是基本的想法:
// Store a list of attempts
var attempts = new List<DateTime>();
// Determine if 10 or more attempts have been made in the last 5 minutes
bool lockout = attempts.Where(a => (DateTime.Now - a).TotalMinutes <= 5).Count() >= 10;
// Register an attempt
attempts.Add(DateTime.Now);
// Remove attempts older than 5 minutes
attempts.Where(a => (DateTime.Now - a).TotalMinutes > 5).ToList()
.ForEach(a => attempts.Remove(a));
您还可以将尝试存储在数据库中,这样可以为您提供安全性的papertrail。同样的方法适用 - 计算不到5分钟的记录。
答案 2 :(得分:1)
答案取决于您如何解释要求。也就是说,5分钟的时间框架是否为滑动尺度?
严格应用该要求将要求您为登录尝试创建数据库表,每条记录包括用户记录的密钥和登录尝试的时间戳。然后,对于每次尝试,执行类似
的查询delete from login_attempts where user=[user] and attempt_time<[now - 5 minutes]
select count(*) from login_attempts where user=[user]
(括号中的值被替换为合适的值,无论您是使用预备陈述还是其他任何内容)
然后,如果返回的计数&gt; 10,你阻止了这次尝试。
(我建议每次都删除旧的尝试以保持桌子清洁。当然,替代方法是可能的。)
如果不需要严格执行要求并且您不想创建新表,则可以通过例如将最后尝试时间和计数添加到用户记录来简化它。然后在每次尝试(伪代码在这里......):
read last_attempt and attempt_count
if last_attempt < now - 5 minutes then
attempt_count=0
endif
if attempt_count>10 then
display error
else if attempt_fails then
last_attempt=now
attempt_count=attempt_count+1
endif
这不会严格符合规定的要求:如果用户每4分钟尝试一次,那么在40分钟后我们会说他有10次不良尝试,而实际上只有一次超过5分钟。但它会更简单,然后创建一个新的表,并实现我认为的目标,阻止某人通过蛮力破解密码。
答案 3 :(得分:0)
要实现滑动的5分钟窗口,您需要知道每次尝试的时间,而不仅仅是第一次或最后一次。
每次登录尝试都存储在数据库中。正如评论中提到的那样,只是简单地使用会话缓存。
username | time
mr.mindor | 00:00:00
mr.mindor | 00:01:00
等。 然后对于每次登录尝试检查有10次或更少的尝试...
Select count(*)
from LOGIN_ATTEMPTS
where username = @current_user
AND time > DATEADD(m,-5,GetDate())
您可以无限期地保留LOGIN_ATTEMPTS用于安全/审核目的,或定期清除,或成功登录。
仅存储第一次或最后一次和计数的问题。
没有每次,您无法确定尝试的分布。
基于第一次尝试的解决方案:
只需第一次尝试时间和计数,您可以在第一次尝试后的5分钟内防止超过10次尝试,但在任何给定的5分钟间隔内不会阻止超过10次尝试。
例如:你可以在0:00和9在4:59获得1,并在几秒钟内在5:01获得10以上19。
attempt_time | record
0:00 | {0:00, 1}
4:59 | {0:00, 2}
4:59 | {0:00, 3}
4:59 | {0:00, 4}
4:59 | {0:00, 5}
4:59 | {0:00, 6}
4:59 | {0:00, 7}
4:59 | {0:00, 8}
4:59 | {0:00, 9}
4:59 | {0:00, 10}
5:01 | {5:00, 1} // 10 since 4:59
5:02 | {5:00, 2} // 11 since 4:59
基于最后尝试的解决方案:
只保存最后一次尝试时间和计数,您可以在任何5分钟间隔内防止超过10次尝试,但实际上它更具限制性。在前一次尝试的5分钟内,每次尝试都会超过10次
示例:如果每4分钟尝试一次,您的计数器将永远不会重置。
attempt_time | record
0:00 | {0:00, 1}
4:00 | {4:00, 2} // 2 in last 5 minutes
8:00 | {8:00, 3} // 2 in last 5 minutes
...
40:00 | {40:00,11} // blocked but only 2 in last 5 minutes.
答案 4 :(得分:0)
这里的计时器太丑了。 只需保留某种Attempts表。 存储UserId,尝试时间和成功/失败标志。
从那里逻辑是自我解释的。