代码之家  ›  专栏  ›  技术社区  ›  Zifre

有没有可能防止在谷歌应用引擎上加药?

  •  17
  • Zifre  · 技术社区  · 15 年前

    我正在考虑为谷歌应用引擎开发一个应用程序,它不应该获得太多流量。我真的不想花钱超过免费配额。然而,似乎很容易通过超载应用程序和超过配额来引起拒绝服务攻击。有没有什么方法可以防止或使其更难超过免费配额?我知道,例如,我可以限制来自一个IP的请求数量(使其难以超过CPU配额),但是有没有任何方法可以使其更难超过请求或带宽配额?

    5 回复  |  直到 7 年前
        1
  •  16
  •   Achille    15 年前

    没有内置的工具来防止DOS。如果使用Java编写谷歌应用程序,则可以使用 service.FloodFilter 过滤器。下面的代码将在任何servlet执行之前执行。

    package service;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    
    
    /**
     * 
     * This filter can protect web server from simple DoS attacks
     * via request flooding.
     * 
     * It can limit a number of simultaneously processing requests
     * from one ip and requests to one page.
     *
     * To use filter add this lines to your web.xml file in a <web-app> section.
     * 
        <filter>
            <filter-name>FloodFilter</filter-name>
            <filter-class>service.FloodFilter</filter-class>
            <init-param>
                <param-name>maxPageRequests</param-name>
                <param-value>50</param-value>
            </init-param>
            <init-param>
                <param-name>maxClientRequests</param-name>
                <param-value>5</param-value>
            </init-param>
            <init-param>
                <param-name>busyPage</param-name>
                <param-value>/busy.html</param-value>
            </init-param>
        </filter>
    
        <filter-mapping>
            <filter-name>JSP flood filter</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
     *  
     *  PARAMETERS
     *  
     *  maxPageRequests:    limits simultaneous requests to every page
     *  maxClientRequests:  limits simultaneous requests from one client (ip)
     *  busyPage:           busy page to send to client if the limit is exceeded
     *                      this page MUST NOT be intercepted by this filter
     *  
     */
    public class FloodFilter implements Filter
    {
        private Map <String, Integer> pageRequests;
        private Map <String, Integer> clientRequests;
    
        private ServletContext context;
        private int maxPageRequests = 50;
        private int maxClientRequests = 10;
        private String busyPage = "/busy.html";
    
    
        public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException
        {
            String page = null;
            String ip = null;
    
            try {
                if ( request instanceof HttpServletRequest ) {
                    // obtaining client ip and page URI without parameters & jsessionid
                    HttpServletRequest req = (HttpServletRequest) request;
                    page = req.getRequestURI();
    
                    if ( page.indexOf( ';' ) >= 0 )
                        page = page.substring( 0, page.indexOf( ';' ) );
    
                    ip = req.getRemoteAddr();
    
                    // trying & registering request
                    if ( !tryRequest( page, ip ) ) {
                        // too many requests in process (from one client or for this page) 
                        context.log( "Flood denied from "+ip+" on page "+page );
                        page = null;
                        // forwarding to busy page
                        context.getRequestDispatcher( busyPage ).forward( request, response );
                        return;
                    }
                }
    
                // requesting next filter or servlet
                chain.doFilter( request, response );
            } finally {
                if ( page != null )
                    // unregistering the request
                    releaseRequest( page, ip );
            }
        }
    
    
        private synchronized boolean tryRequest( String page, String ip )
        {
            // checking page requests
            Integer pNum = pageRequests.get( page );
    
            if ( pNum == null )
                pNum = 1;
            else {
                if ( pNum > maxPageRequests )
                    return false;
    
                pNum = pNum + 1;
            }
    
            // checking client requests
            Integer cNum = clientRequests.get( ip );
    
            if ( cNum == null )
                cNum = 1;
            else {
                if ( cNum > maxClientRequests )
                    return false;
    
                cNum = cNum + 1;
            }
    
            pageRequests.put( page, pNum );
            clientRequests.put( ip, cNum );
    
            return true;
        }
    
    
        private synchronized void releaseRequest( String page, String ip )
        {
            // removing page request
            Integer pNum = pageRequests.get( page );
    
            if ( pNum == null ) return;
    
            if ( pNum <= 1 )
                pageRequests.remove( page );
            else
                pageRequests.put( page, pNum-1 );
    
            // removing client request
            Integer cNum = clientRequests.get( ip );
    
            if ( cNum == null ) return;
    
            if ( cNum <= 1 )
                clientRequests.remove( ip );
            else
                clientRequests.put( ip, cNum-1 );
        }
    
    
        public synchronized void init( FilterConfig config ) throws ServletException
        {
            // configuring filter
            this.context = config.getServletContext();
            pageRequests = new HashMap <String,Integer> ();
            clientRequests = new HashMap <String,Integer> ();
            String s = config.getInitParameter( "maxPageRequests" );
    
            if ( s != null ) 
                maxPageRequests = Integer.parseInt( s );
    
            s = config.getInitParameter( "maxClientRequests" );
    
            if ( s != null ) 
                maxClientRequests = Integer.parseInt( s );
    
            s = config.getInitParameter( "busyPage" );
    
            if ( s != null ) 
                busyPage = s;
        }
    
    
        public synchronized void destroy()
        {
            pageRequests.clear();
            clientRequests.clear();
        }
    }
    

    如果您使用的是python,那么您可能需要滚动自己的过滤器。

        2
  •  7
  •   Jeremy Logan    15 年前

    我不确定是否可能,但是 App Engine FAQs 指出如果你能证明这是DoS攻击,那么他们会退还与攻击相关的任何费用。

        3
  •  2
  •   Alex sashkello    12 年前

    看来他们有一个基于IP地址的过滤器既可以用于Python和Java现在(我知道这是一个老线程,但它仍然上升到高的谷歌搜索)。

    https://developers.google.com/appengine/docs/python/config/dos

        4
  •  1
  •   Tad Hunt    8 年前

    始终可以在应用程序引擎应用程序前使用提供拒绝服务保护功能的服务。例如,CloudFlare提供了一种备受尊重的服务 https://www.cloudflare.com/waf/ 还有其他的。我的理解是(免责声明:我没有亲自使用服务),这些功能在免费计划中可用。

    在应用程序本身中构建基于memcache的速率限制实现也相当容易。这是我在谷歌搜索这个方法时得到的第一个结果: http://blog.simonwillison.net/post/57956846132/ratelimitcache .这种机制是健全的,并且可以经济有效,因为共享memcache的使用可能足够并且是免费的。此外,走这条路会让你控制旋钮。缺点是应用程序本身必须处理HTTP请求并决定允许或拒绝它,因此可能需要花费(或[免费]配额耗尽)来处理。

    完全公开:我在谷歌的应用引擎工作,与CloudFlare或SimonWillison没有任何联系。

        5
  •  1
  •   Dan Cornilescu    7 年前

    这个 GAE firewall 是最近发布的,旨在取代以前的,相当有限的, DoS Protection Service .

    它支持通过(rest)管理API编程更新防火墙规则: apps.firewall.ingressRules 它可以与应用程序内的一段逻辑相结合,用于DOS检测,如其他答案中所述。不同之处在于,一旦部署了规则,违规请求将不再产生费用,因为它们不再到达应用程序,因此不需要应用程序内过滤本身。