如何限制每秒的Web请求以避免垃圾邮件和拒绝服务

时间:2015-09-14 09:23:22

标签: java tomcat web spam-prevention denial-of-service

我有一个网页,它接受用户的搜索查询并在数据库中搜索它。由于此查询非常耗时,即使使用适当的索引,我也希望将搜索请求限制为每个用户每2秒1次。目前我正在使用以下方法(粗略草图)

限制:
1)我的网站中没有登录系统。相反,我依赖于请求标头来获取用户的IP地址和用户ID。

Algo:

1) Maintain a map of ips and user ids and their latest search timestamp.
2) For every search request, 
   2.1) If user has searched in last two seconds: Show error message
   2.2) Else, allow him to search

我想知道这种方法是否足够?由于IP地址和用户ID都来自请求标头,垃圾邮件发送者是否可以更改请求标头?

1 个答案:

答案 0 :(得分:0)

这是一个简单的servlet过滤器,可以防止用户在一段时间内访问资源(可能需要改进):

// (requires http sessions enabled)
public class AccessControlFilter implements Filter {

private final String ACCESS_CONTROL_SESSION_KEY = String.valueOf("NextAccessAllowedTime".hashCode());

// how long to prevent users from accessing in ms?
private final long penaltyTime = 1000 * 2;

@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    // is http request?
    if (req instanceof HttpServletRequest) {
        HttpSession session = ((HttpServletRequest) req).getSession();

        // has access value in session?
        Object value = session.getAttribute(ACCESS_CONTROL_SESSION_KEY);
        if (value != null) {

            Date nextAccessAllowed = new Date(((long) value));
            if (new Date().before(nextAccessAllowed)) {

                // handle access denied (better redirect to another url or display message then sending this response code?)
                ((HttpServletResponse) res).sendError(HttpServletResponse.SC_FORBIDDEN, "Access to this resource is denied until: " + nextAccessAllowed);
                res.flushBuffer();
                return;
            }
        }
        session.setAttribute(ACCESS_CONTROL_SESSION_KEY, System.currentTimeMillis() + penaltyTime);
    }
    chain.doFilter(req, res);
}

@Override
public void init(FilterConfig config) throws ServletException {
    System.out.println("Starting " + this.getClass().getSimpleName() + " on resource: \"" + config.getServletContext().getFilterRegistration(config.getFilterName()).getUrlPatternMappings().iterator().next() + "\" with penalty time: "
            + penaltyTime + "ms!");
}

@Override
public void destroy() {
    System.out.println("Stopping " + this.getClass().getSimpleName());
}
}

在web.xml中启用它,如下所示:

<filter>
    <filter-name>acf</filter-name>
    <filter-class>your.package.AccessControlFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>acf</filter-name>
    <!-- Resource to check. Should be the url your search form posts to! -->
    <url-pattern>/search/*</url-pattern>
</filter-mapping>

如果您正在寻找http服务器级别的模块,请查看&#34; mod evasive&#34;。

也许您应该尝试缓存搜索结果(即ehcache)并创建修复线程池来处理搜索,这样您就可以一次控制搜索量。