博客评论接口被恶意刷评论问题记录

博客评论接口被恶意刷评论问题记录

问题回顾

前两天,打开博客,发现评论区,出现好多奇怪的评论,非正常评论,而且时间间隔就几秒,这就显示有人使用其他手段恶意刷评论。
image.png
想着可能就是谁无聊而已。放了几天,没想到他还天天刷,这就有点过分。所以需要给博客防护下了。

nginx限制ip

1、首先查看nginx的日志

image.png

通过日志分析,发现这个恶意的评论都是来自 109.70.100.*,这个ip网段。
所以,可以通过nginx的deny,限制ip。

2、配置如下:

image.png

这样就可以限制109.70.100.*,这个网段的所有ip。

3、结果如下:

image.png

这是这个ip访问的就拦截了。

网关限制

虽然nginx,已经可以帮助我们拦截IP了,但是当ip数量多,还有一些敏感词汇的拦截等等,所以自己用springcloud的zuul,搭建一个网关。

1、新建一个springboot的项目,加入pom
   <!--zuuljar包-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>

   <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
2、增加配置文件 application.yml
zuul:
  routes:
     eureka-application-service.path: /**
     eureka-application-service.url: http://127.0.0.1:8080
  max:
     host:
       connections: 500
  host:
     socket-timeout-millis: 60000
     connect-timeout-millis: 60000

server:
  port: 8091

eureka:
  client:
     register-with-eureka: false
     fetch-registry: false

security:
  basic:
    enabled: false

fengpt:
  blackIp: "109.70.100.*"
  sensitive:
  urlList: "/api/content/posts/comments"
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 600000

ribbon:
  ReadTimeout: 600000
  ConnectTimeout: 600000
logging:
  # 将日志输出到文件 注意name和path同时使用只会生效后一个配置
  file: "/usr/local/apps/fengptzuul/logs/log.log"
    # 日志文件大小默认是10M单位是KB
    #max-size: 10MB
    # 每天切割打包日志的数量默认是7
    #max-history: 7
  #日志格式
  pattern:
    #输出到日志文件日志格式
    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
    #输出到控制台日志格式
    #  %clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
    #时间格式 默认 yyyy-MM-dd HH:mm:ss.SSS
    dateformat: "yyyy-MM-dd HH:mm:ss.SSS"
    #日志等级对齐方式 默认%5p日志级别输出右对齐
    level:
    #切割文件名称 默认是${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz 如过单个日志文件超过定义的大小就切割打包
    rolling-file-name: "${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz"
  #需要记录日志的等级
  level:
    # 根目录所以class日志记录等级
    root: info
    # 自定义对应包下class 日志等级
    cn.fengpt.gateway.filter.GateWayFilter: info
说明:
  • blackIp: 填写需要拦截的ip,可以是多个以逗号分隔
  • sensitive: 填写需要拦截的敏感词汇,可以是多个以逗号分隔
  • urlList: 填写需要拦截的url,可以是多个以逗号分隔

3、启动类加EnableZuulProxy

@SpringBootApplication
@EnableZuulProxy
public class FengptGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(FengptGatewayApplication.class, args);
    }

}

4、编写拦截规则

@Component
public class GateWayFilter extends ZuulFilter {


    private static Logger log = LoggerFactory.getLogger(GateWayFilter.class);

    @Value("${fengpt.blackIp}")
    private String blackIp;

    @Value("${fengpt.sensitive}")
    private String sensitive;

    @Value("${fengpt.urlList}")
    private String urlList;


    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        log.info(String.format("blackIp:%s >>>  ;sensitive: %s",blackIp,sensitive));
        String ip= getIpAddress(request);
        log.info(String.format("ip >>> %s", ip));
        boolean flag = ipPattern(blackIp, ip);
        if (!flag){
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            try {
                ctx.getResponse().getWriter().write("Illegal request");
            }catch (Exception e){}
            return null;
        }
       String url= request.getRequestURL().toString();
       if(StringUtils.isNotBlank(url)&&StringUtils.isNotBlank(urlList)){
            boolean flag2 = urlPattern(urlList,url);
            if(!flag2){
                try{
                                         // 获取请求的输入流
                    InputStream in = request.getInputStream();
                    String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
                    log.info(String.format("body >>> %s",  body));
                    boolean flag1 =sensitivePattern(sensitive,body);
                    if (!flag1){
                        ctx.setSendZuulResponse(false);
                        ctx.setResponseStatusCode(401);
                        try {
                            ctx.getResponse().getWriter().write("Illegal request");
                        }catch (Exception e){
                        }
                        return null;
                    }
                }catch(Exception e){

                }
            }
       }
        log.info("ok");
        return null;

    }



     /**
     * 获取Ip地址
     * @param request
     * @return
     */
    private static String getIpAddress(HttpServletRequest request) {
        String Xip = request.getHeader("X-Real-IP");
        String XFor = request.getHeader("X-Forwarded-For");
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            //多次反向代理后会有多个ip值,第一个ip才是真实ip
            int index = XFor.indexOf(",");
            if(index != -1){
                return XFor.substring(0,index);
            }else{
                return XFor;
            }
        }
        XFor = Xip;
        if(StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)){
            return XFor;
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_CLIENT_IP");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
            XFor = request.getRemoteAddr();
        }
        return XFor;
    }



    public static boolean sensitivePattern(String sensitives,String body) {
        boolean flag=true;
        if (StringUtils.isNotBlank(sensitives)&&StringUtils.isNotBlank(sensitives)){
            List<String> tbList = Arrays.asList(sensitives.split(","));
            if (tbList!=null&&tbList.size()!=0){
                for (int i=0;i<tbList.size();i++){
                    if(body.contains(tbList.get(i))){
                        flag=false;
                        break;
                    }
                }
            }
        }
        return flag;
    }


    public static boolean urlPattern(String urlList,String url) {
            boolean flag=true;
            if (StringUtils.isNotBlank(urlList)&&StringUtils.isNotBlank(url)){
                List<String> tbList = Arrays.asList(urlList.split(","));
                if (tbList!=null&&tbList.size()!=0){
                    for (int i=0;i<tbList.size();i++){
                        if(url.contains(tbList.get(i))){
                            flag=false;
                            break;
                        }
                    }
                }
            }
            return flag;
    }


    /**
     * 过滤ip
     * @param ips
     * @param ip
     * @return
     */
    public static boolean ipPattern(String ips,String ip) {
        boolean flag=true;
        if (StringUtils.isNotBlank(ips)&&StringUtils.isNotBlank(ip)){
            String[] split = ips.split(",");
            if (split!=null&&split.length!=0){
                for (int i=0;i<split.length;i++){
                    if(Pattern.matches(split[i],ip)){
                        flag=false;
                        break;
                    }
                }
            }
        }
        return flag;
    }
}

5、测试

编译打包成jar,后运行。

image.png

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.fengpt.cn/archives/博客评论接口被恶意刷评论问题记录