网站验证防攻击,当ip验证次数大于10,或者电话验证次数大于5.就添加黑名单。并24小时后恢复
首先,我们创建一个对象,存储ip的验证次数和验证时间
@AllArgsConstructor
@NoArgsConstructor
public class CountAndTime {
Integer Count;
LocalDateTime time;
public Integer getCount() {
return Count;
}
public CountAndTime setCount(Integer count) {
Count = count;
return this;
}
public LocalDateTime getTime() {
return time;
}
public void setTime(LocalDateTime time) {
this.time = time;
}
}
通过创建一个map类型的数据合适,key存储的是ip地址或者电话。value存放以上次数和时间对象
Map<String,CountAndTime> ipCount = new HashMap<>();
Map<String,CountAndTime> telCount = new HashMap<>();
以下为ip和电话的限制次数,并达到24小时后恢复限制的方法,限制返回flase。通过返回true
/**
* ip限制次数
* @param request
* @return
* @throws UnknownHostException
*/
public Boolean IpRestrict (HttpServletRequest request) {
Map<String,Object> res = new HashMap<>();
String ip = HttpUtil.getIp(request); //获取访问ip
if (ipCount.get(ip)==null){
ipCount.put(ip, new CountAndTime(1, LocalDateTime.now())); //如果ip未验证,则添加到map,次数为1
}else{
ipCount.put(ip,ipCount.get(ip).setCount(ipCount.get(ip).getCount()+1)); //如果已经验证,访问次数+1
Duration between = Duration.between(ipCount.get(ip).getTime(), LocalDateTime.now()); //比较两个时间的分钟差
if (between.toMinutes()>=1440){ //如果大于1440分钟,24小时。则重新更新当前ip时间为当前,次数为1
ipCount.put(ip, new CountAndTime(1, LocalDateTime.now()));
}
}
return ipCount.get(ip).getCount() <= 10; //当验证次数大于10,则限制该ip,返回false
}
/**
* 电话限制次数
* @return
* @throws UnknownHostException
*/
public Boolean TelRestrict (String tel) {
Map<String,Object> res = new HashMap<>();
if (telCount.get(tel)==null){
telCount.put(tel, new CountAndTime(1, LocalDateTime.now())); //如果ip未验证,则添加到map,次数为1
}else{
telCount.put(tel,telCount.get(tel).setCount(telCount.get(tel).getCount()+1)); //如果已经验证,访问次数+1
Duration between = Duration.between(telCount.get(tel).getTime(), LocalDateTime.now()); //比较两个时间的分钟差
if (between.toMinutes()>=1440){ //如果大于1440分钟,24小时。则重新更新当前ip时间为当前,次数为1
telCount.put(tel, new CountAndTime(1, LocalDateTime.now()));
}
}
return telCount.get(tel).getCount() <= 5; //当验证次数大于10,则限制该ip,返回false
}
网站页面请求防攻击逻辑代码(带注释)
需要用到httpUtil工具类,请前往我的另一篇文章获取。传送门
public class SafetyFilter implements HandlerInterceptor {
@Value("${SafetyFilter.reCount}")
String reCountStr="10";
@Value("${SafetyFilter.temporal}")
String temporalStr="3";
@Value("${SafetyFilter.lockTime}")
String lockTimeStr="15";
Integer lockTime=Integer.valueOf(lockTimeStr);
Integer reCount=Integer.valueOf(reCountStr); //请求次数
Integer temporal=Integer.valueOf(temporalStr); //时间频率
Map<String,RequestIp> re = new HashMap<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
PrintWriter out = null;//返回给页面显示
//取用户的真实IP
String ip = HttpUtil.getIp(request);
RequestIp requestIp = re.get(ip);
//第一次请求
if(null == requestIp){ //如果对象为空,则新建对象,放入map中
RequestIp reIp = new RequestIp();
reIp.setCreateTime(System.currentTimeMillis());
reIp.setReCount(1);
re.put(ip,reIp);
}else{ //如果不是第一次请求
Long createTime = requestIp.getCreateTime(); //获取第一次请求的创建时间
if (re.get(ip).getReCount()==0){ //当次数等于零的时候,就知道是锁住了
if ((System.currentTimeMillis()-re.get(ip).getCreateTime())/1000>lockTime*60){ //如果锁定的时间与现在的时间相差15分钟,就解锁
re.put(ip, re.get(ip).setReCount(1));
}
return false;
}
if(((System.currentTimeMillis() - createTime)/1000) > temporal){ //如果请求的频率大于3s,直接放行
System.out.println("通过请求!"+((System.currentTimeMillis() - createTime)/1000));
//当前时间离上一次请求时间大于3秒,可以直接通过,保存这次的请求
RequestIp reIp = new RequestIp();
reIp.setCreateTime(System.currentTimeMillis());
reIp.setReCount(1); //并且请求次数重新设置为1
re.put(ip, reIp);
return true;
}else{
//小于3秒,并且3秒之内请求了10次,返回提示
if(requestIp.getReCount() > reCount){
request.getSession().setAttribute("reqcode",503);
request.getSession().setAttribute("reqmsg","请求太快,请稍后再试!");
re.put(ip, new RequestIp(System.currentTimeMillis(),0)); //锁定ip
return false;
}else{
//小于3秒,但请求数小于10次,给对象添加
requestIp.setCreateTime(System.currentTimeMillis());
requestIp.setReCount(requestIp.getReCount()+1);
re.put(ip,requestIp);
return true;
}
}
}
return true;
}
// 在业务处理器处理请求完成之后,生成视图之前执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception{
}
// 在DispatcherServlet完全处理完请求之后被调用,可用于清理资源
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception{
}
}