2009-05-04 1 views
16

Google App Engine 용 앱을 개발하려고합니다. 너무 많은 트래픽을 발생 시켜서는 안됩니다. 나는 정말로 무료 쿼터를 초과하여 지불하지 않을 것입니다. 그러나 앱 과부하 및 할당량 초과로 인해 서비스 거부 공격이 발생할 수있는 것처럼 보입니다. 무료 할당량을 초과하는 것을 방지하거나 어렵게 만들 수있는 방법이 있습니까? 예를 들어 IP에서 요청하는 수를 제한하여 (CPU 할당량을 초과하는 것이 어렵게 만들 수 있음), 요청이나 대역폭 할당량을 초과하는 것을 어렵게 만들 수있는 방법이 있습니까?Google App Engine에서 DoSing을 방지 할 수 있습니까?

답변

16

DoS를 방지하는 기본 제공 도구가 없습니다. 자바를 사용하여 Google Apps를 작성하는 경우 service.FloodFilter 필터를 사용할 수 있습니다. 다음 코드는 서블릿이 수행되기 전에 실행됩니다. 에서

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

당신이 파이썬을 사용하는 경우에, 당신은 당신의 자신의 필터를 롤백 할 수 있습니다.

+0

나는 여분의 속도를 위해 아마도 자바를 사용할 것이므로 이것이 도움이 될 것이다. – Zifre

+0

App Engine에 DoS 필터가 지원되었습니다. –

+3

DOS 필터는 알려진 IP에서만 작동합니까? 공격이 시작되기 전에 IP가 알려지지 않은 DDoS 공격은 처리 할 수 ​​없습니다. 또한 위 예제는 정적 리소스 대역폭 사용을 보호 할 수 없습니다. –

7

가능한지 확실하지 않지만 App Engine FAQs은 DOS 공격임을 표시 할 수 있다면 공격과 관련된 모든 수수료를 환불 해 준다는 것을 나타냅니다.

+0

감사합니다 ... 만약 내가 지불한다면, 그것은 저에게이 이슈에 대해 훨씬 더 나아지게 할 것입니다. – Zifre

+3

결제를 사용 설정하지 않으면 무료 할당량을 초과하면 단기간 (하루 종일 미만) 동안 사이트가 오프라인 상태가됩니다. 명시 적으로 사용하도록 설정 한 경우에만 청구되며 청구 범위는 직접 설정할 수 있습니다. –

+3

하나의 IP에서 고정 파일 다운로드 (20MB x 600 시간, 2 시간)와 같은 도스 공격을 경험했으며 환불을 요청했으며 거부 했다며 DOS 공격으로 간주되지 않습니다. 그리고 당신이 설정 한 일일 예산에 도달하여 서비스가 중단되면 이것은 "거부"로 간주되지 않습니다. Google이 문제를 해결할 때까지 지금은 DOS 공격으로부터 시스템을 보호하는 방법을 고안하는 것이 좋습니다. –

2

그들은 IP 주소 기반 필터를 파이썬과 자바 모두 사용할 수있는 것으로 보입니다. (오래된 스레드 인 것을 알고 있지만 여전히 Google 검색에서 높은 것으로 나타납니다).

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

+3

이것은 모든 DDoS 공격에 유용하지는 않지만 사용자 수는 해당 도구로 차단할 수있는 1000 IP보다 훨씬 큽니다. 새로운 공격자가 공격에 관여하기 때문에 몇 분마다 웹 사이트를 다시 업로드해야합니다. –

1

이 앱 엔진 애플리케이션의 앞에 서비스 보호 기능의 거부를 제공하는 서비스를 사용하는 것이 가능하다. 예를 들어, Cloudflare는 훌륭한 서비스 인 https://www.cloudflare.com/waf/을 제공하며 다른 서비스도 있습니다. 이 기능을 무료로 사용할 수 있다는 것은 저의 이해입니다 (면책 조항 : 서비스를 개인적으로 사용하지는 않았습니다).

응용 프로그램 자체에서 memcache 기반 속도 제한 구현을 구성하는 것도 매우 쉽습니다. 다음은이 방법에 대한 Google 검색에서 얻은 첫 번째 히트입니다. http://blog.simonwillison.net/post/57956846132/ratelimitcache. 이 메커니즘은 소리가 나며 공유 memcache 사용이 충분하고 무료이기 때문에 비용면에서 효과적 일 수 있습니다. 또한이 경로를 사용하면 손잡이를 제어 할 수 있습니다. 단점은 애플리케이션 자체가 HTTP 요청을 처리하고 허용 또는 거부하도록 결정해야하므로 처리 할 비용 (또는 [무료] 할당량 소모)이있을 수 있다는 것입니다.

전체 공개 : 저는 Google App Engine에서 근무하며 Cloudflare 또는 Simon Willison과 관련이 없습니다.

1

GAE firewall은 최근에 발표되어 다소 제한적이었던 이전의, DoS Protection Service을 대체하기위한 것입니다.

(REST) ​​Admin API : apps.firewall.ingressRules을 통해 방화벽 규칙의 프로그래밍 방식 업데이트를 지원하며, 다른 답변에 설명 된대로 DoS 탐지를위한 인앱 응용 프로그램과 결합 될 수 있습니다. 차이점은 규칙이 배포되고 나면 더 이상 앱에 도달하지 않아 문제의 요청이 더 이상 발생하지 않으므로 인앱 필터링 자체가 필요하지 않습니다.