📚 Теория: Webhook + Regex DoS (раскрыть)
Сигнатура через регексп
Выражение ^([A-Fa-f0-9]+:)+[A-Fa-f0-9]+$ содержит вложенные квантификаторы. Длинная подпись заставляет JVM перебирать варианты.
⚠️ ReDoS на уровне заголовков, блокировка Netty/Servlet потока.
Лучшие практики
Используй HexFormat или DatatypeConverter.parseHexBinary, добавь @Size(max=64), pre-check длины, лимит на заголовки и rate limit.
🔐 Подписи лучше проверять детерминированно, без backtracking.
Интеграция шлёт заголовок из 200k символов `AA:`.
Регексп на бэктрекинге зависает и блокирует обработку.
Платёжные вебхуки не доходят, RTO срывается.
Как надо: ограничь длину заголовков, используй `HexFormat.of().parseHex`, rate limit, circuit breaker и тесты с ReDoS-строками.
Контекст
Партнёрский шлюз требует подпись `sha256:nonce`. Разработчик сделал простой регексп, но не ограничил длину и не добавил таймаут. Результат — ReDoS при длинном заголовке.
- Найди строку с
@Patternдля подписи. - Предложи заменить на
HexFormat, добавить@Size(max=128), лимиты в reverse-proxy. - Предложи тесты: MockMvc + заголовок 100k символов, ожидать 400 без зависаний.
Сниппет
Code Review
Референс-исправление
Откажись от тяжёлого регекспа, проверь подпись детерминированно и лимитируй заголовки.
Флаг ревью: FLAG{java-redos-webhook}
@PostMapping
public ResponseEntity<Void> receive(
@RequestHeader("X-Signature")
@Size(max = 128)
String signature,
@RequestBody String payload) {
String[] parts = signature.split(":", 2);
if (parts.length != 2) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST); }
byte[] sig = HexFormat.of().parseHex(parts[1]);
verifier.verify(sig, payload);
return ResponseEntity.ok().build();
}
Добавь в gateway ограничение на заголовки, unit-тесты с длинной подписью и фуззинг регекспов.
Проверка флага
После ревью зафиксируй флаг, чтобы дашборд засчитал лабораторию.