目标
我正在使用RESTEasy框架设置RESTful Web服务。为了安全起见,我使用Apache Shiro。我希望我的api停止接受请求或超时登录的人。
问题
每当我使用浏览器(chrome)访问某些URL时,我都可以尝试无限次登录。似乎是一个非常糟糕的主意,允许这样做。作为一项措施,我确保记住nr次登录尝试,用户3次后无法登录。但是,通过暴力攻击,您仍然可以阻止所有用户登录。我想要一个更通用的解决方案。
Shiro.ini
[main]
# We store users and passwords inside the realm.
myRealm = com.myproject.shiro.DatabaseRealm
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
[urls]
/api/version = anon
/api/** = authcBasic
DatabaseRealm
public class DatabaseRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// No clue what to do with this functin. I only use authentication and not authorization, so probably just nothing.
return null;
}
/**
* Check if the user inputted is valid. The user can login if holds:
* 1. Password is correct. (if not, nrOfLogonAttempts++)
* 2. LogonUser.nrOfLogonAttemps is less than 3
* 3. LogonUser.dateEndValid is null or >= today.
* @param authenticationToken Token with basic information.
* @return SimpleAuthenticationInfo
* @throws AuthenticationException Whenever the user cannot login.
*/
@SuppressWarnings("ConstantConditions")
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws UnknownAccountException, IncorrectCredentialsException, LockedAccountException, ExpiredCredentialsException {
// Connect with the database.
DbContext context = null;
try {
context = DbContextUtil.getContextFromTomcat();
// Lookup user in the database.
LogonUserMyDao logonUserMyDao = new LogonUserMyDao(context);
LogonuserPojo logonuserPojo = logonUserMyDao.fetchOneByUsername(((UsernamePasswordToken) authenticationToken).getUsername());
if (logonuserPojo == null) {
throw new UnknownAccountException("Could not find user.");
}
// Check password
String plainTextPassword = new String(((UsernamePasswordToken) authenticationToken).getPassword());
if (!BCryptUtil.checkPassword(plainTextPassword, logonuserPojo.getPassword())) {
// We will note this event.
logonuserPojo.setNroflogonattempts(logonuserPojo.getNroflogonattempts() + 1);
logonUserMyDao.update(logonuserPojo);
context.commit();
throw new IncorrectCredentialsException("Incorrect password.");
}
// Check nrOfLogonAttempts
if (logonuserPojo.getNroflogonattempts() >= 2) {
throw new LockedAccountException("Cannot login anymore.");
}
// Check date
if (logonuserPojo.getDateendvalid() != null && DateTimeUtil.isBeforeToday(logonuserPojo.getDateendvalid())) {
throw new ExpiredCredentialsException("Account is expired.");
}
// User is valid, so return some info.
return new SimpleAuthenticationInfo(logonuserPojo.getUsername(), plainTextPassword, getClass().getName());
} catch (SQLException e) {
MyLogger.logError("Could not connect to user database.", e);
throw new AuthenticationException("Could not connect to databse.");
} finally {
if (context != null) {
try {
context.getConnection().close();
} catch (SQLException e) {
MyLogger.logError("Could not close connection", e);
}
}
}
}
}
答案 0 :(得分:0)
您是否在寻找更一般的DDOS保护?根据应用程序的运行位置(例如AWS Shield),有一些选项可供选择。
您还可以使用以下内容阻止连接到达您的数据库:https://github.com/iTransformers/ddos-servlet-filter(但是,仍然需要在您的应用程序中处理请求)
在Shiro方面,计算你的尝试并不是一个坏主意,但你需要注意用户管理方面的事情(用户如何解锁,支持请求?等待30分钟?)而不是记录失败,您可能只想记录/审核所有尝试(当然不包括实际密码)。使用任一选项调用支持或n
分钟窗口,这可能有助于提供一些支持或简单查询的上下文。