分享

java 实现IP访问量控制

 zhengyoucai 2015-04-25

同一个IP 访问网站, 不能同时超过配置的最大值, 可以用来保护REST IP 或者DOS攻击


 


Java代码 复制代码 收藏代码
  1. /* 
  2.  * Pprun's Public Domain. 
  3.  */  
  4. package org.pprun.common.security;  
  5.   
  6. import java.io.IOException;  
  7. import java.util.Collections;  
  8. import java.util.HashMap;  
  9. import java.util.HashSet;  
  10. import java.util.Map;  
  11. import java.util.Set;  
  12. import javax.servlet.Filter;  
  13. import javax.servlet.FilterChain;  
  14. import javax.servlet.FilterConfig;  
  15. import javax.servlet.ServletException;  
  16. import javax.servlet.ServletRequest;  
  17. import javax.servlet.ServletResponse;  
  18. import javax.servlet.http.HttpServletResponse;  
  19. import org.slf4j.Logger;  
  20. import org.slf4j.LoggerFactory;  
  21. import org.springframework.beans.factory.annotation.Required;  
  22. import org.springframework.jmx.export.annotation.ManagedAttribute;  
  23. import org.springframework.scheduling.annotation.Scheduled;  
  24.   
  25. /** 
  26.  * A filter to throttle only a limited number of requests from the same ip per second. 
  27.  * <p> 
  28.  * Two parameters need to inject: 
  29.  * <ol> 
  30.  * <li>common.throttle.maxConcurrentRequests=10</li> 
  31.  * <li>common.throttle.period=1000</li> 
  32.  * </ol> 
  33.  * <br /> 
  34.  * If you use {@literal Spring} for {@lit DI}, it can be done as below in application {@literal web.xml}: 
  35.  * <br /> 
  36.  * {@code  
  37.  *      <filter>   
  38.  *          <description>A filter to throttle only a limited number of requests from the same ip per second.</description>   
  39.  *          <filter-name>throttleFilter</filter-name>   
  40.  *          <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>   
  41.  *      </filter> 
  42.  * } 
  43.  * <br /> 
  44.  * And a bean with {@code id="throttleFilter"} should be defined in {@literal application.xml}. 
  45.  * </p> 
  46.  * @author <a href="mailto:pizhigang@letv.com">pizhigang</a> 
  47.  */  
  48. //@Component  
  49. public class ThrottleFilter implements Filter, ThrottleFilterMXBean {  
  50.   
  51.     private static Logger log = LoggerFactory.getLogger(ThrottleFilter.class);  
  52.     // map(ip, requestCount)  
  53.     private Map<String, Integer> ip2countCache = new HashMap<String, Integer>();  
  54.     private Set<String> blackList = new HashSet<String>();  
  55.     private int maxConcurrentRequests;  
  56.     private static final long PERIOD = 1L; // second  
  57.     private boolean enable = false;  
  58.   
  59.     @Override  
  60.     public void init(FilterConfig config) throws ServletException {  
  61.         // nothing  
  62.     }  
  63.   
  64.     @Override  
  65.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain nextFilter) throws ServletException, IOException {  
  66.         if (enable) {  
  67.             final String ip = request.getRemoteAddr();  
  68.             boolean isOverflow;  
  69.   
  70.             synchronized (this) {  
  71.                 Integer count = ip2countCache.get(ip);  
  72.   
  73.                 if (count == null || count.intValue() == 0) {  
  74.                     count = 0;  
  75.                 }  
  76.   
  77.                 if (count < maxConcurrentRequests) {  
  78.                     isOverflow = false;  
  79.                     ip2countCache.put(ip, count + 1);  
  80.                 } else {  
  81.                     isOverflow = true;  
  82.                     blackList.add(ip);  
  83.                 }  
  84.             }  
  85.   
  86.             if (isOverflow) {  
  87.                 // block it  
  88.                 log.info(" ip {} has reached the threshold {} in {} second, block it!"new Object[]{ip, maxConcurrentRequests, PERIOD});  
  89.   
  90.                 if (response instanceof HttpServletResponse) {  
  91.                     ((HttpServletResponse) response).sendError(503, ip + " has too many concurrent requests per " + PERIOD + " second");  
  92.                 }  
  93.                 return;  
  94.             }  
  95.         } // else go ahead below  
  96.   
  97.         // every thing is okay, go ahead  
  98.         nextFilter.doFilter(request, response);  
  99.     }  
  100.   
  101.     // every 1 second  
  102.     @Scheduled(fixedRate = PERIOD * 1000)  
  103.     public void throttlingJob() {  
  104.         if (enable) {  
  105.             log.debug("Throttle Filter clean up job is running");  
  106.             synchronized (ThrottleFilter.this) {  
  107.                 for (Map.Entry<String, Integer> ip2count : ip2countCache.entrySet()) {  
  108.                     Integer count = ip2count.getValue();  
  109.                     String ip = ip2count.getKey();  
  110.   
  111.                     if (count == null || count <= 1) {  
  112.                         ip2countCache.remove(ip);  
  113.                     } else {  
  114.                         if (count == maxConcurrentRequests) {  
  115.                             // remove from blacklist  
  116.                             log.info("Throttle Filter: removing {} from black list", ip);  
  117.                             blackList.remove(ip);  
  118.                         }  
  119.   
  120.                         ip2countCache.put(ip, count - 1);  
  121.                     }  
  122.                 }  
  123.             }  
  124.             log.debug("Throttle Filter clean up job is done");  
  125.         }  
  126.     }  
  127.   
  128.     /** 
  129.      * Any cleanup for the filter. 
  130.      */  
  131.     @Override  
  132.     public void destroy() {  
  133.         log.warn("destorying Throttle Filter");  
  134.     }  
  135.   
  136.     /** 
  137.      * Sets the maximum number of concurrent requests for a single IP. 
  138.      */  
  139.     @Required  
  140.     public void setMaxConcurrentRequests(int max) {  
  141.         maxConcurrentRequests = max;  
  142.     }  
  143.   
  144.     @ManagedAttribute(description = "is the throttle filter enable or not")  
  145.     @Override  
  146.     public boolean isEnable() {  
  147.         return enable;  
  148.     }  
  149.   
  150.     @Required  
  151.     @Override  
  152.     public void setEnable(boolean enable) {  
  153.         log.info("set enable to {}", enable);  
  154.         if (enable == false) {  
  155.             log.info("Throttle filter will be disabled");  
  156.         }  
  157.   
  158.         this.enable = enable;  
  159.     }  
  160.   
  161.     public Set<String> getBlackList() {  
  162.         // for exactly, it might need synchronized, but no hurt for snapshoot in one or severl seconds  
  163.         return Collections.unmodifiableSet(blackList);  
  164.     }  
  165. }  

 


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多