2009-05-04 36 views
16

Tôi đang xem xét việc phát triển một ứng dụng cho Google App Engine, không nên nhận quá nhiều lưu lượng truy cập. Tôi thực sự không muốn trả tiền vượt quá hạn ngạch miễn phí. Tuy nhiên, có vẻ như nó sẽ khá dễ dàng để gây ra một cuộc tấn công từ chối dịch vụ bằng cách quá tải ứng dụng và vượt quá hạn ngạch. Có bất kỳ phương pháp nào để ngăn chặn hoặc làm cho khó vượt quá hạn ngạch miễn phí không? Tôi biết tôi có thể, ví dụ, giới hạn số lượng yêu cầu từ một IP (làm cho nó khó vượt quá hạn ngạch CPU), nhưng có cách nào để làm cho nó khó vượt quá yêu cầu hoặc hạn ngạch băng thông không?Có thể ngăn chặn DoSing trên Google App Engine không?

Trả lời

16

Không có công cụ tích hợp để ngăn chặn DoS. Nếu bạn đang viết Google Apps bằng java thì bạn có thể sử dụng bộ lọc service.FloodFilter. Đoạn mã sau đây sẽ thực hiện trước khi bất kỳ Servlets nào của bạn thực hiện.

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

Nếu bạn đang sử dụng python, sau đó bạn có thể phải cuộn lọc của riêng bạn.

+0

Tôi có thể sẽ sử dụng Java cho tốc độ thêm, vì vậy điều này có thể hữu ích. – Zifre

+0

App Engine đã hỗ trợ bộ lọc DoS trong một thời gian. –

+3

Bộ lọc DOS chỉ hoạt động đối với IP đã biết phải không? Nó không thể đối phó với các cuộc tấn công DDOS mà IP không được biết trước khi tấn công bắt đầu. Ngoài ra, ví dụ trên không thể bảo vệ sử dụng băng thông tài nguyên tĩnh –

7

Tôi không chắc chắn nếu có thể, nhưng App Engine FAQs cho biết rằng nếu bạn có thể hiển thị đó là một cuộc tấn công DOS thì họ sẽ hoàn lại bất kỳ khoản phí nào liên quan đến vụ tấn công.

+0

Cảm ơn ... nếu tôi đã trả tiền, điều đó sẽ khiến tôi cảm thấy tốt hơn về vấn đề này. – Zifre

+3

Trừ khi bạn bật thanh toán, vượt quá hạn ngạch miễn phí sẽ chỉ đưa trang web của bạn ngoại tuyến trong một khoảng thời gian ngắn (ít hơn nhiều so với cả ngày). Nó sẽ chỉ lập hóa đơn cho bạn nếu bạn đã kích hoạt một cách rõ ràng và bạn có thể đặt giới hạn thanh toán của riêng mình. –

+3

Tôi đã trải qua tấn công DOS khi tải xuống tệp tĩnh (khoảng 20MB x 600 lần trong 2 giờ) từ một IP duy nhất, tôi đã yêu cầu hoàn lại tiền và từ chối, nói điều này không được coi là tấn công DOS. Và họ nói rằng nếu dịch vụ dừng lại vì đạt đến ngân sách hàng ngày bạn đặt, điều này không được coi là "từ chối". Tôi muốn nói rằng chúng tôi nên phát minh ra cách riêng của mình để bảo vệ khỏi tấn công DOS ngay bây giờ cho đến khi Google khắc phục được sự cố của họ. –

2

Dường như họ có bộ lọc dựa trên địa chỉ IP có sẵn cho cả Python và Java ngay bây giờ (tôi biết đây là một chuỗi cũ nhưng vẫn xuất hiện cao trên tìm kiếm của Google).

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

+3

Điều này không hữu ích trong bất kỳ tấn công DDoS nào, số lượng người dùng lớn hơn nhiều so với 1000 IP mà bạn có thể chặn bằng công cụ đó. Chưa kể rằng bạn phải tải lên lại trang web của bạn sau mỗi vài phút khi những kẻ tấn công mới tham gia vào cuộc tấn công. –

1

Đó là luôn luôn có thể sử dụng một dịch vụ cung cấp Denial of Service tính năng bảo vệ trước một ứng dụng App Engine. Ví dụ: Cloudflare cung cấp dịch vụ được tôn trọng https://www.cloudflare.com/waf/ và có những dịch vụ khác. Đó là sự hiểu biết của tôi (từ chối trách nhiệm: Tôi đã không sử dụng dịch vụ cá nhân) rằng các tính năng này có sẵn trên gói miễn phí.

Cũng khá dễ dàng để xây dựng một triển khai hạn chế tốc độ dựa trên memcache trong chính ứng dụng của bạn. Đây là lần truy cập đầu tiên tôi nhận được từ tìm kiếm trên google cho phương thức này: http://blog.simonwillison.net/post/57956846132/ratelimitcache. Cơ chế này là âm thanh, và có thể có hiệu quả về chi phí khi sử dụng memcache dùng chung có thể đủ và miễn phí. Hơn nữa, đi tuyến đường này sẽ giúp bạn kiểm soát các nút bấm. Hạn chế là bản thân ứng dụng phải xử lý yêu cầu HTTP và quyết định cho phép hoặc từ chối nó, vì vậy có thể có chi phí (hoặc [miễn phí] hạn ngạch hết hạn) để giải quyết.

Tiết lộ đầy đủ: Tôi làm việc tại Google trên App Engine và không có liên kết với Cloudflare hoặc Simon Willison.

1

Đã phát hành gần đây GAE firewall, nhằm thay thế trước đó, thay vì giới hạn, DoS Protection Service.

Nó hỗ trợ cập nhật có lập trình các quy tắc tường lửa qua API quản trị (REST): apps.firewall.ingressRules có thể được kết hợp với một đoạn logic trong ứng dụng để phát hiện DoS như được mô tả trong các câu trả lời khác. Sự khác biệt sẽ là khi quy tắc được triển khai, các yêu cầu vi phạm sẽ không còn phát sinh phí khi chúng không tiếp cận ứng dụng nữa, do đó, chính tính năng lọc trong ứng dụng là không cần thiết.

Các vấn đề liên quan