我想得到关于以下内容的建议:
我在 Tomcat上使用jsp web-application ,用户在输入登录名和密码后(两者都是自动定义而不是在创建帐户后更改)能够进入他们的个人页面。
我想在服务器上使用带有用户登录ID的 ArrayList 对用户帐户进行一些保护,其中某些登录ID的登录成功次数将保持不变(将有线程制作金额值)一段时间后为零)。
如果金额大于某个定义的值 - 阻止登录(直到金额清理)并发送到用户电子邮件链接,点击服务器内部的金额值将设置为0。我将继续努力,但我的问题是,这种方法是否正确,ArrayList
将满足需求:
List<User> users = Collections.synchronizedList(userList);
并使用同步set
和get
方法访问它
目的是获得针对暴力攻击(手动或甚至服务器驱动)的保护。
有没有办法防范访问攻击(在短时间内进行多次登录尝试)?
提前致谢。
答案 0 :(得分:0)
一个可以轻松抵御暴力攻击的简单方法是添加 salt 和 pepper 。这些基本上是随机字符附加到密码和/或用户名,这使得蛮力成功的几率降低了很多。
This维基百科文章讨论了该方法的一般基础。
答案 1 :(得分:0)
并使用synchronized set和get方法访问它。
您如何从这样的列表中获取用户?在每次登录尝试期间,您必须遍历整个列表以找到该用户,或者您始终知道数组中的确切位置,或者可能是列表已排序,因此您可以使用二进制搜索,但在这种情况下,插入在复杂性方面效率低下。 此外,必须同步用户结构或存储最新失败登录的位置。
Imho在实现方面最简单的解决方案之一可能如下。请注意,在一段时间之后不需要额外的线程来重置尝试次数,但是在一段时间内您必须清除最近失败的登录时间超出可观察时间范围的对。导致结构增长的其他方式。ConcurrentHashMap<String, List<Long>> loginFails = new ConcurrentHashMap<>();
int ATTEMPTS_TO_FREEZE = 5;
int TIME_FRAME_IN_MINUTES = 5;
以登录为密钥,并将最后一次失败登录的列表作为值。在我们的例子中,让阈值为5。 登录前检查权限。如果5在最后5分钟内失败 - &gt;拒绝
List<Long> attempts = loginFails.get(login);
if (attempts != null) {
synchronized(attempts) {
if (attempts.size() == ATTEMPTS_TO_FREEZE
&& attempts.peek() > System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(TIME_FRAME_IN_MINUTES)) {
//return some warning to user, that he exceeded number of attempts
}
}
}
登录失败后
Queue<Long> attempts = loginFails.get(login);
if (attempts == null) {
attempts = loginFails.putIfAbsent(login, new LinkedList<Long>());
if (attempts == null) {
attempts = loginFails.get(login);
}
}
synchronized (attempts) {
attempts.add(System.currentTimeMillis());
if (attempts.size() > ATTEMPTS_TO_FREEZE) {
attempts.remove();
}
}
在重置时(点击电子邮件链接后),您只需删除具有此类登录的条目即可。您也可以存储id或其他任何内容(而不是String键)(但要确保密钥类具有等于哈希码的契约并且是不可变的)
另请注意,如果有人试图破解大量登录,此方案将不会非常有效。 代码中可能存在一些错误,但我希望你能说明问题。
答案 2 :(得分:0)
我不太了解java足以为您提供代码。
但是,如果您可以使用IP地址存储请求,则可以在其上设置特殊规则(如防火墙)。
说,当同一个IP在一分钟内发送100个请求时,您可以禁止它访问您的网站。
已经给出的一个好建议是在回答之前增加延迟。如果必须测试数百万个密码才能找到有效的密码,那么每增加一秒就会使暴力攻击非常耗时。