記一次博客被惡意刷留言處理方式

前言:

博客被惡意刷留言了,致使短期內沒法正常訪問,並讓我博客的留言板看起來比較糟,本覺得攻擊者只是一時興起,看我有開放接口,就攻擊測試一下,可次日博客又受到了攻擊,第三天仍是如此,看樣子是被盯上了,更可惡的是還利用留言回覆自動發郵件功能,留下一個公司的郵箱地址,致使經過個人博客做死的給那個公司郵箱回覆郵件(好像是狂神公司的郵箱地址,實在是抱歉)。哎,林子大了什麼鳥都有,也見慣不怪,畢竟能作這種事的人心理是有點問題的,估計是小時候有過什麼陰影,致使人格扭曲了那麼一點,說實話,挺可憐這種人的,悲哀!java

博客中留言功能是沒有作限制的,初衷就是讓全部人都可以在這個平臺暢所欲言,不作限制,可這也給了一些人可乘之機,例如上面那位惡意刷留言的,那咱們要如何作防禦呢,既要作到不受限制的留言,又不能讓人惡意刷留言,沒錯,就是攔截器了,我們能夠指定某個接口在指定的時間內訪問的次數受到限制。以一個Springboot工程爲例,我們來說述一下如何攔截。redis

【0】建立Springboot工程

使用idea搭建Springboot工程spring

yml配置文件:apache

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    timeout: 1800000
    lettuce:
      pool:
        max-active: 20
        max-wait: -1
        max-idle: 5
        min-idle: 0
複製代碼

主要的pom依賴:json

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- spring2.X集成redis所需common-pool2-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.6.0</version>
</dependency>
<!-- json解析-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.28</version>
</dependency>
複製代碼

【1】自定義一個註解

咱們自定義一個註解,能夠將這個註解做用在要攔截接口的方法上,當在接口的方法上加了這個註解後,就能夠按照指定的規則進行攔截,以下:markdown

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface AccessLimit {
    int seconds();
    int maxCount();
}
複製代碼

這裏註解類上的三個註解稱爲元註解,其分別表明的含義以下:session

  • @Documented:註解信息會被添加到Java文檔中
  • @Retention:註解的生命週期,表示註解會被保留到什麼階段,能夠選擇編譯階段、類加載階段,或運行階段
  • @Target:註解做用的位置,ElementType.METHOD表示該註解僅能做用於方法上

在自定義註解類中,定義了兩個方法,seconds()、maxCount(),表示指定時間內請求的次數app

  • seconds():表示指定的時間內
  • maxCount():表示請求的次數

【2】自定義一個攔截器

  • 經過自定義的註解傳遞指定時間和請求次數
  • 使用redis記錄請求次數
  • 當訪問次數達到指定上限的時候進行限制
@Component
public class SessionInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 判斷請求是否屬於方法的請求
        if (handler instanceof HandlerMethod) {
            HandlerMethod hm = (HandlerMethod) handler;
            // 獲取方法中的註解,看是否有該註解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if (null == accessLimit) {
                return true;
            }

            // 指定時間內
            int seconds = accessLimit.seconds();
            // 容許請求次數
            int maxCount = accessLimit.maxCount();

            String ip=request.getRemoteAddr();
            String key = request.getServletPath() + ":" + ip ;

            // 從redis中獲取用戶訪問的次數
            Integer count = (Integer) redisTemplate.opsForValue().get(key);

            System.out.println(count);

            if (null == count || -1 == count) {
                // 第一次訪問
                redisTemplate.opsForValue().set(key, 1,seconds, TimeUnit.SECONDS);
                return true;
            }

            if (count < maxCount) {
                // count加1
                count = count+1;
                redisTemplate.opsForValue().set(key, count,0);
                return true;
            }

            // 超出訪問次數
            if (count >= maxCount) {
                // response 返回 json 請求過於頻繁請稍後再試
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json; charset=utf-8");
                Response result = new Response<>();
                result.setCode("9999");
                result.setMsg("操做過於頻繁");
                Object obj = JSONObject.toJSON(result);
                response.getWriter().write(JSONObject.toJSONString(obj));
                return false;
            }
        }

        return true;
    }
}
複製代碼

【3】將攔截器註冊到容器中

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Autowired
    private SessionInterceptor sessionInterceptor;
    @Bean
    public SessionInterceptor tokenVerifyInterceptor() {
        return new SessionInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(sessionInterceptor);
        registry.addInterceptor(tokenVerifyInterceptor()).addPathPatterns("/**");
        WebMvcConfigurer.super.addInterceptors(registry);
    }
}
複製代碼

【4】測試

編寫controller進行測試ide

@RestController
public class TestController {
    @GetMapping("test")
    @AccessLimit(seconds = 15, maxCount = 3) //15秒內 容許請求3次
    public String testAccessLimit() {

        return "success";
    }
}
複製代碼

爲了方便顯示,對返回結果進行處理:spring-boot

public class Response<T> implements Serializable {
    private static final long serialVersionUID = -4505655308965878999L;

    //請求成功返回碼爲:0000
    private static final String successCode = "0000";
    //返回數據
    private T data;
    //返回碼
    private String code;
    //返回描述
    private String msg;

    public Response(){
        this.code = successCode;
        this.msg = "請求成功";
    }

    public Response(String code,String msg){
        this();
        this.code = code;
        this.msg = msg;
    }
    public Response(String code,String msg,T data){
        this();
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public Response(T data){
        this();
        this.data = data;
    }

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public static String getSuccessCode() {
        return successCode;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
複製代碼

訪問:http://localhost:8080/test,能夠看到正常請求和頻繁刷新請求的結果:

image-20210124232246874

image-20210124232422974

到這裏就差很少了,最後放一下整個工程的目錄結構:

image-20210124232612248

這裏仍是得感謝攻擊我博客的那我的,讓我對攔截功能更熟悉了

打不倒你的,只會讓你更強大!

相關文章
相關標籤/搜索