安全顶部

我刚宣布了新的学习春天安全课程,包括Spring Security 5中新的OAuth2堆栈的完整材料:

>>查看课程

1.概述

在这个快速教程中,我们将实现一个基本的解决方案防止强行验证尝试使用Spring安全。

简单地说,我们将记录来自单个IP地址的失败尝试次数。如果这个特定的IP超过了一定数量的请求-它将被封锁24小时。

进一步阅读:

Spring方法安全性简介

使用Spring安全框架的方法级安全指南。

Spring安全滤波链中的自定义过滤器

快速指南,展示在Spring Security上下文中添加自定义过滤器的步骤。

针对响应性应用程序的Spring Security 5

Spring Security 5框架的快速实用示例,用于确保无功应用的功能。

2.一个AuthenticationFailureListener

让我们从定义an开始AuthenticationFailureListener- 听听AuthenticationFailureBadCredentialsEvent事件,并在认证失败时通知我们:

@Component public class AuthenticationFailureListener implements ApplicationListener;@Autowired private LoginAttemptService;@Override public void onApplicationEvent(AuthenticationFailureBadCredentialsEvent e) {final String xfHeader = request.getHeader(" x - forwarder - for ");if (xfHeader == null) {loginAttemptService.loginFailed(request.getRemoteAddr());} else {loginAttemptService.loginFailed(xfHeader.split(",")[0]);}}}

注意如何,当认证失败时,我们通知loginattemptservice.从未成功尝试起源的IP地址的IP地址。在这里,我们从中获取IP地址httpservletrequest.豆,它也给我们发起了始发地址X-Forthed-for用于转发的请求的标题。代理服务器。

3.AuthenticationSuccessEventListener

我们也定义anAuthenticationSuccessEventListener-它监听身份验证CessEvent.事件,并通知我们成功的身份验证:

@component公共类验证ucescesseventlistener实现applicationlistener  {@autowired private httpservletRequest请求;@Autowired private LoginAttemptService;@override公共void onApplicationEvent(最终身份验证鉴别e){最终字符串xfheader = request.getheader(“X-Forthed-for”);if(xfheader == null){loginattemptservice.loginsucceeded(request.getRemoteaddr());} else {loginattemptservice.loginsucceeded(xfheader.split(“,”)[0]);}}}

请注意——与失败侦听器类似,我们正在通知loginattemptservice.认证请求发起的IP地址的IP地址。

4.loginattemptservice.

现在 - 让我们讨论我们的loginattemptservice.实施;简单地说,我们在24小时内保持每个IP地址错误尝试的次数:

@Service public class LoginAttemptService {private final int MAX_ATTEMPT = 10;private LoadingCache attemptsCache;public LoginAttemptService() {super();attemptsCache = CacheBuilder.newBuilder()。TimeUnit.DAYS expireAfterWrite(1)。public Integer load(String key) {return 0;}});} public void loginSucceeded(String key) {attemptsCache.invalidate(key);} public void loginFailed(String key) {int attempts = 0;try {attempts = attemptsCache.get(key); } catch (ExecutionException e) { attempts = 0; } attempts++; attemptsCache.put(key, attempts); } public boolean isBlocked(String key) { try { return attemptsCache.get(key) >= MAX_ATTEMPT; } catch (ExecutionException e) { return false; } } }

注意不成功的身份验证尝试会增加该IP的尝试次数,成功的身份验证将重置该计数器。

从这一点来看,这只是一个问题在验证时检查计数器

5.的userdetailsservice.

现在,让我们在我们的自定义中添加额外的支票userdetailsservice.实施;当我们加载时userdetails.,我们首先需要检查此IP地址是否已被阻止:

@Service("userDetailsService") @Transactional public class MyUserDetailsService implements userDetailsService {@Autowired private RoleRepository;@Autowired private LoginAttemptService;@Autowired私有HttpServletRequest请求;@Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {String ip = getClientIP();if (loginAttemptService.isBlocked(ip)){抛出新的RuntimeException("blocked");} try {User User = userRepository.findByEmail(email);if (user == null){返回新的org.springframework.security.core.userdetails。用户(" "," ",true, true, true, true, true, getauthority (array . aslist (roleRepository.findByName("ROLE_USER"))));}返回新的org.springframework.security.core.userdetails。User( user.getEmail(), user.getPassword(), user.isEnabled(), true, true, true, getAuthorities(user.getRoles())); } catch (Exception e) { throw new RuntimeException(e); } } }

这里是getClientIP ()方法:

private String getClientIP() {String xfHeader = request.getHeader(" x - forward - for ");if (xfHeader == null){return request.getRemoteAddr();}返回xfHeader.split (", ") [0];}

注意,我们有一些额外的逻辑确认客户端原IP地址。在大多数情况下,这不是必要的,而是在某些网络场景中,它是。

对于这些罕见的情况,我们使用X-Forthed-for标题到达原始IP;这是此标题的语法:

X-Forwarded-for:clientipaddress,proxy1,proxy2

另外,请注意春天有另一种超级有趣的能力 -我们需要HTTP请求,所以我们只是简单地将其连接进来。

现在,这很酷。我们必须将一个快速的侦听器添加到我们的web.xml.为此工作,它使事情变得更加容易。

  org.springframework.web.context.request.requestContextListener  

这就是它 - 金宝搏官网188be我们已经定义了这个新的RequestContextListener在我们的web.xml.能够从中访问该请求userdetailsservice.

6.修改AuthenticationFailureHandler.

最后 - 让我们修改我们的customauthenticationfailure handler.自定义新的错误消息。

当用户实际确实被阻止24小时时,我们正在处理情况 - 我们向用户通知他的IP被阻止,因为他超出了允许的最大错误身份验证尝试:

@Component公共类CustomauthenticationFailureHandler扩展了SimpleURLAuthenticationFailureHandler {@Autowifired私人MessageSource消息;@override public void onauthenticationFailure(...){string errormessage = messages.getMessage(“message.badcredentials”,null,locale);if(例外.getmessage()。EqualsignOrecase(“被阻止”)){Errormessage = Messages.getMessage(“auth.message.blocked”,null,locale);} ...}}

7.结论

重要的是要明白这是很好的第一步处理Brute-Force密码尝试,但也有改进的空间。一个生产级的暴力阻止策略可能涉及比IP块更多的元素。

全面实施本教程可以找到GitHub项目

安全底部

我刚宣布了新的学习春天安全课程,包括Spring Security 5中新的OAuth2堆栈的完整材料:

>>查看课程
15注释
最老的
最新
内联反馈
查看所有评论
评论在本文上关闭!