Estoy considerando desarrollar una aplicación para Google App Engine, que no debería recibir demasiado tráfico. Prefiero no pagar para exceder las cuotas gratuitas. Sin embargo, parece que sería bastante fácil provocar un ataque de denegación de servicio al sobrecargar la aplicación y exceder las cuotas. ¿Hay algún método para prevenir o dificultar la superación de las cuotas gratuitas? Sé que podría, por ejemplo, limitar el número de solicitudes de una IP (lo que hace más difícil exceder la cuota de la CPU), pero ¿hay alguna manera de hacer que sea más difícil exceder las solicitudes o las cuotas de ancho de banda?¿Es posible evitar DoSing en Google App Engine?
Respuesta
No hay herramientas integradas para evitar el DoS. Si está escribiendo Google Apps usando java, puede usar el filtro service.FloodFilter
. La siguiente pieza de código se ejecutará antes que cualquiera de sus Servlets.
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();
}
}
Si está utilizando Python, entonces puede que tenga que rodar su propio filtro.
No estoy seguro de si es posible, pero el App Engine FAQs indica que si puede demostrar que es un ataque de DOS, entonces le reembolsarán las tarifas asociadas con el ataque.
Gracias ... si tuviera que pagar, me haría sentir mucho mejor sobre este tema. – Zifre
A menos que habilite la facturación, exceder las cuotas gratuitas simplemente desconectará su sitio por un período corto (mucho menos que un día entero). Solo se lo facturará si lo habilitó explícitamente y puede establecer su propio límite de facturación. –
Experimenté un ataque de DOS en una descarga de archivos estáticos (algo así como 20 MB x 600 veces en 2 horas) desde una única IP, pedí un reembolso y se negaron, diciendo que esto no se considera un ataque de DOS. Y dicen que si el servicio se detuvo debido a que alcanzó el presupuesto diario que estableció, esto no se considera como "denegación". Yo diría que es mejor que inventemos nuestra propia forma de protegernos del ataque de DOS por ahora hasta que Google solucione su problema. –
Parece que tienen un filtro basado en la dirección IP disponible tanto para Python como para Java ahora (sé que este es un hilo viejo, pero todavía aparece en una posición alta en una búsqueda de Google).
https://developers.google.com/appengine/docs/python/config/dos
Esto no es útil en ningún ataque DDoS, el número de usuarios es mucho mayor que los 1000 IP que puede bloquear con esa herramienta. Sin mencionar que tienes que volver a cargar tu sitio web cada pocos minutos a medida que los nuevos atacantes se involucran en el ataque. –
Siempre es posible utilizar un servicio que proporciona características de protección de denegación de servicio en frente de una aplicación de App Engine. Por ejemplo, Cloudflare proporciona un servicio muy respetado https://www.cloudflare.com/waf/, y hay otros. Entiendo (descargo de responsabilidad: no he usado el servicio personalmente) que estas funciones están disponibles en el plan gratuito.
También es bastante fácil construir una implementación de límite de velocidad basada en Memcache en su aplicación. Este es el primer golpe que obtuve de una búsqueda en google para este método: http://blog.simonwillison.net/post/57956846132/ratelimitcache. Este mecanismo es sólido y puede ser rentable ya que el uso compartido de Memcache puede ser suficiente y gratuito. Además, seguir esta ruta te permite controlar las perillas. El inconveniente es que la aplicación en sí debe manejar la solicitud HTTP y decidir si la permite o la niega, por lo que puede haber un costo (o agotamiento de la cuota [gratuita]) para tratar.
Divulgación completa: trabajo en Google en App Engine, y no tengo ninguna asociación con Cloudflare o Simon Willison.
Se lanzó recientemente el GAE firewall, destinado a reemplazar el anterior, bastante limitado, DoS Protection Service.
Es compatible con las actualizaciones programáticas de las reglas de firewall a través de la API de administración (REST): apps.firewall.ingressRules que podría combinarse con una pieza de lógica en la aplicación para la detección de DoS como se describe en otras respuestas. La diferencia sería que una vez que se implementa la regla, las solicitudes infractoras ya no incurrirán en cargos ya que no llegan a la aplicación, por lo que el filtrado en la aplicación en sí no es necesario.
- 1. ¿Es posible una encuesta larga en Google App Engine?
- 2. ¿Es posible usar Django 1.2 en Google App Engine?
- 3. Django + Pydev/Eclipse + Google App Engine: ¿es posible?
- 4. Google App Engine: ¿es posible hacer una consulta Gql LIKE?
- 5. Google App Engine Locking
- 6. Jinja2 en Google App Engine
- 7. Google App Engine
- 8. Google-app-engine NDB
- 9. Google App Engine Geohashing
- 10. Google App Engine: get_or_create()?
- 11. Google app engine & CDN
- 12. Google App Engine: ¿Cuál es su RDBMS?
- 13. Google App Engine: ¿quién es un administrador?
- 14. ¿Google App Engine es adecuado para mí?
- 15. ¿Qué tan rápido es Google App Engine?
- 16. ¿Google App Engine es compatible con ftp?
- 17. web.py en Google App Engine
- 18. appengine_config.py en Google App Engine
- 19. eCommerce en Google App Engine
- 20. Google App Engine en Silverlight
- 21. Django en Google App Engine
- 22. Google App Engine en Google Apps Domain
- 23. Google Maps y Google App Engine
- 24. Google App Engine retraso extraño
- 25. debería dejar Google App Engine?
- 26. MVC en Google App Engine Java world
- 27. Pretty URLs en Google App Engine
- 28. Google App Engine: appcfg.py rollback
- 29. Google App Engine: autenticación personalizada
- 30. Google App Engine: módulo JSON
Probablemente voy a usar Java para la velocidad extra, por lo que esto podría ayudar. – Zifre
App Engine cuenta con soporte para filtro DoS desde hace un tiempo. –
El filtro DOS solo funciona para IP conocida ¿verdad? No puede tratar con ataques DDOS que IP no se conocen antes de que comience el ataque. Además, el ejemplo anterior no puede proteger el uso del ancho de banda de los recursos estáticos –