Напиши анти ддос на джава
Ответ нейросети
12 января 2026 19:04
Ниже приведено простое, понятное решение на Java для защиты веб-приложения от попыток DDoS за счет ограничения количества запросов от одного IP за фиксированный временной период (фиксированное окно). Это пример учебного уровня, который можно расширять и адаптировать под реальные проекты. Он подходит для общего среднего школьного уровня и не требует специальных знаний сервера.
Как работает идея:
- Для каждого IP хранится окно времени и количество запросов в этом окне.
- Если за текущее окно количество запросов меньше порога, запрос разрешается.
- Если достигнут порог, дальнейшие запросы в этом окне отклоняются с кодом 429 (Too Many Requests).
- Окно считается по минутам (или по любому заданному значению windowMs).
Важно: это базовый пример. Для продакшна стоит рассмотреть более продвинутые решения (распределенный кэш, интеграцию с прокси/балансировщиком, разные алгоритмы и т.д.).
Шаги реализации:
- Создаем простой RateLimiter, который хранит для каждого IP окно и счётчик.
- Добавляем Servlet Filter, который применяет rate limiter к входящим HTTP-запросам.
- В конфигурации указываем параметры: maxRequests и windowMs.
Пример кода
- RateLimiter (помощник, потокобезопасный базовый вариант)
import java.util.concurrent.ConcurrentHashMap;
public class SimpleRateLimiter {
// Максимальное число запросов за окно
private final int maxRequests;
// Длительность окна в миллисекундах
private final long windowMs;
// Карта IP -> запись лимита
private final ConcurrentHashMap<String, RateLimitEntry> map = new ConcurrentHashMap<>();
public SimpleRateLimiter(int maxRequests, long windowMs) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
}
// Возвращает true, если можно обработать запрос, false — если перегружено
public boolean allow(String ip) {
long currentWindow = System.currentTimeMillis() / windowMs; // номер текущего окна
RateLimitEntry entry = map.get(ip);
if (entry == null) {
RateLimitEntry newEntry = new RateLimitEntry(currentWindow, 0);
RateLimitEntry existing = map.putIfAbsent(ip, newEntry);
if (existing != null) {
entry = existing;
} else {
entry = newEntry;
}
}
synchronized (entry) {
// если окно сменилось, сбрасываем счётчик
if (entry.windowStart != currentWindow) {
entry.windowStart = currentWindow;
entry.count = 0;
}
if (entry.count < maxRequests) {
entry.count++;
return true;
} else {
// достигнут лимит в текущем окне
return false;
}
}
}
// Вспомогательный класс записи per-IP
static class RateLimitEntry {
volatile long windowStart;
volatile int count;
RateLimitEntry(long windowStart, int count) {
this.windowStart = windowStart;
this.count = count;
}
}
}
- Servlet Filter для применения лимита
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RateLimitFilter implements Filter {
private SimpleRateLimiter limiter;
@Override
public void init(FilterConfig config) throws ServletException {
// Пример конфигурации по умолчанию. Можно вынести в web.xml или параметры окружения.
int maxRequests = 100; // пример: 100 запросов
long windowMs = 60_000; // за 60 секунд
limiter = new SimpleRateLimiter(maxRequests, windowMs);
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String ip = request.getRemoteAddr();
if (limiter.allow(ip)) {
chain.doFilter(req, res);
} else {
HttpServletResponse response = (HttpServletResponse) res;
response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
response.setContentType("text/plain");
response.getWriter().write("Too many requests. Please slow down.");
}
}
@Override
public void destroy() {
// ничего особого
}
}
- Как подключить (вариант настройки)
- В веб-приложении (web.xml):
<filter>
<filter-name>RateLimitFilter</filter-name>
<filter-class>RateLimitFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RateLimitFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- Или в Spring Boot можно сделать как фильтр через регистрацию бина, например:
- аннотировать класс @Component и добавить @WebFilter (для сервлетов) или регистрировать через FilterRegistrationBean.
- можно инъектировать параметры maxRequests и windowMs из application.properties.
- Что можно улучшать (варианты для расширения)
- Переключение на Sliding Window вместо Fixed Window для более плавной скорости ограничения.
- Использование Token Bucket или Leaky Bucket алгоритмов.
- Распределенный лимит по нескольким серверам через Redis или распределенную кеш‑систему.
- Интеграция с прокси/балансировщиком: Nginx/HAProxy могут выполнять часть ограничения до попадания запросов в приложение.
- Добавление списков белых/черных IP, временных исключений для администраторов, CAPTCHA/челленджей после достижения порога и т.д.
- Логирование и мониторинг количества отклонённых запросов для анализа нагрузки.
Замечания и предостережения
- Это базовый учебный пример, не рассчитанный на продакшн‑использование без доработок.
- В реальной инфраструктуре рекомендуется использовать распределённый лимит по нескольким машинам (Redis, Memcached) и/или внешний прокси.
- Всегда тестируйте под нагрузкой в безопасной среде, чтобы не блокировать легитимные пользователи.
Если хочешь, могу адаптировать этот пример под конкретный стек (Spring Boot, Jakarta EE, обычный сервлет‑контейнер) или разобрать более продвинутые алгоритмы/решения под твою задачу. Также могу привести примеры тестирования нагрузки и как проверить работоспособность лимита.
Понравился ответ?
Задай свой вопрос
Напиши любую задачу или вопрос, а нейросеть её решит



