Pergunta

Estou pensando em desenvolver um aplicativo para o Google App Engine, que não deve ficar muito tráfego. Eu realmente prefiro não pagar para exceder as quotas livres. No entanto, parece que seria muito fácil para causar um ataque de negação de serviço, sobrecarregando o aplicativo e excedendo as cotas. Há algum método para prevenir ou tornar mais difícil de ultrapassar as quotas livres? Eu sei que eu poderia, por exemplo, limitar o número de pedidos a partir de um IP (tornando-o mais difícil de ultrapassar a quota CPU), mas existe alguma maneira de torná-lo mais difícil de ultrapassar as solicitações ou quotas de largura de banda?

Foi útil?

Solução

Não há built-in ferramentas para prevenir DoS. Se você estiver escrevendo Google Apps usando java, então você pode usar o filtro service.FloodFilter. O seguinte pedaço de código será executado antes de qualquer um dos seus Servlets fazer.

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();
    }
}

Se você estiver usando python, então você pode ter que rolar o seu próprio filtro.

Outras dicas

Eu não tenho certeza se é possível, mas a App Engine FAQs indicam que se você pode mostrar que é um ataque DOS, em seguida, eles vão reembolsar todas as taxas associadas com o ataque.

Parece que eles têm um filtro com base endereço IP disponível para Python e Java agora (eu sei que isso é uma discussão antiga, mas ainda aparece no alto de uma pesquisa do Google).

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

É sempre possível utilizar um serviço que fornece Negação de recursos de proteção de serviço na frente de uma aplicação App Engine. Por exemplo, Cloudflare oferece um serviço bem respeitado https://www.cloudflare.com/waf/ , e há outros. É meu entendimento. (Disclaimer: Eu não usei o serviço pessoalmente) que esses recursos estão disponíveis no plano gratuito

Também é bastante fácil de construir uma taxa baseada memcache limitar a execução em sua própria aplicação. Aqui está o primeiro hit que recebi de uma pesquisa no google para este método: http://blog.simonwillison.net / post / 57956846132 / ratelimitcache . Este mecanismo é som, e pode ser rentável como o uso memcache compartilhada pode ser suficiente e é gratuito. Além disso, esse caminho coloca você no controle dos botões. A desvantagem é que o próprio aplicativo deve lidar com o pedido HTTP e decidir permitir ou negar, portanto, pode haver custo (ou [livre] esgotamento da quota) para lidar com eles.

Divulgação completa:. Eu trabalho no Google no App Engine, e não têm associação com Cloudflare ou Simon Willison

O GAE firewall foi lançado recentemente, destina a substituir o anterior, bastante limitado, DoS Protection Service .

Ele suporta atualizações programáticas das regras de firewall através do (REST) ??API Admin: apps.firewall.ingressRules que poderia ser combinado com uma parte na aplicação da lógica para a detecção de negação de serviço, tal como descrito em outras respostas. A diferença seria que uma vez que a regra é implantado os pedidos de ofensa deixarão de ter custos como eles não atingem o aplicativo mais, de modo que o in-app filtragem em si não é necessária.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top