通常的項目 若是沒有作防刷 容易被人爆接口 或者就是說沒有作token防刷過濾。前端
容易被人用正常的token刷接口。有些token非一次性。java
用戶登陸以後生成token會有一個過時時間,但通常沒有作頻率檢查,每訪問一次,會延長這個token時間,刷新用戶狀態web
另外一種就是養號,拿着真實的token,哪怕你是5分鐘 1分鐘。redis
不少的網站找回密碼的接口是沒有作防刷的,只是檢查token是否正常。spring
經過驗證碼認證當前用戶,是否爲當前用戶。sql
前幾天,就用多線程刷過一個三方網站的找回密碼。成功改掉密碼。安全
通常的網站在改密碼的接口都會先查一次此號碼是否已經註冊,相反就能夠經過這個接口猜出真實的用戶手機號,多線程
而後多線程調這個接口猜驗證碼,通常爲4位,複雜點的爲6位。也會有一些項目加了圖形拖拽(第三方)app
前端會提交相關信息給第三方平臺,分析你是否是正常的用戶動做,直接封IP。nosql
可是用戶體驗差一點,有些網站爲了用戶體驗,忽略了網站安全性,看業務上的取捨了。
進入正題:簡易版(demo)
aop 實現 :
package com.zhouixi.serviceA.aspect; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.swing.text.Keymap; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import com.zhouixi.serviceA.annotation.LimitKey; @Component @Order @Aspect public class LimitAspect { private Map limitMap = new HashMap(); private static final Logger log = LoggerFactory.getLogger(LimitAspect.class); @Pointcut("@annotation(limitKey)") public void limit(LimitKey limitKey) { } @Around("limit(limitKey)") public Object aroundLog(ProceedingJoinPoint joinpoint,LimitKey limitKey) throws Throwable { MethodSignature methodSignature = (MethodSignature) joinpoint.getSignature(); int frequency = limitKey.frequency(); String methodName = limitKey.methodName(); String paramKey = limitKey.paramKey(); String url = limitKey.url(); //入參 String[] parameterNames = methodSignature.getParameterNames(); Object[] args = joinpoint.getArgs(); Object obj = null ; for(int i = 0 ; i < parameterNames.length;i++) { if(parameterNames[i].equals(paramKey)) { obj = args[i]; break; } } System.err.println("args : "+Arrays.toString(args)); System.err.println("keys : "+Arrays.toString(parameterNames)); StringBuffer sb = new StringBuffer(); sb.append(url).append("/_").append(methodName).append("_").append(paramKey).append("_").append(obj).append("_key"); if(limitMap.get(sb.toString()) == null ) { limitMap.put(sb.toString(),frequency-1); } else { int l = (int) limitMap.get(sb.toString()); if(l > 0){ limitMap.put(sb.toString(), --l); } else { throw new Exception ("系統繁忙,請重試"); } } //reids 代替map redis.set(sb.toString(),frequency,limitKey.timeout()); System.err.println("剩餘次數:"+limitMap.get(sb.toString())+"----->----->----->自定義key:"+sb.toString()); return joinpoint.proceed(); } }
controller:
註解聲明:
效果圖:
最後一次:
postman:
完成。真實生產場景要換成redis 其餘nosql