Перед каждым API-запросом клиент решает вычислительную задачу (100-500ms CPU). Сервер проверяет решение за микросекунды. Единственная техника, которая линейно масштабирует стоимость скрейпинга с количеством запросов.
Принцип
1. Клиент запрашивает challenge: GET /api/challenge
2. Сервер отдаёт: { challenge: "abc123", difficulty: 4 }
3. Клиент в Web Worker перебирает nonce:
SHA256(challenge + nonce) должен начинаться с N нулей
4. Клиент отправляет API-запрос с решением в заголовке
5. Сервер верифицирует за микросекунды (одно SHA256)
6. Challenge одноразовый — replay невозможен
Экономика
| Действие | Стоимость |
|---|---|
| 1 запрос | ~200ms CPU клиента |
| 1000 запросов | ~200 секунд CPU |
| Полный дамп (10 000 запросов) | ~33 минуты CPU |
Для обычного пользователя (10-50 запросов за сессию) — незаметно. Для скрапера — дорого. Масштабирование бот-фермы требует пропорционального увеличения CPU.
ALTCHA
Self-hosted, open-source, GDPR-friendly альтернатива reCAPTCHA и Cloudflare Turnstile. Нет зависимости от третьих сторон.
- npm:
altcha(сервер) +altchaWeb Component (клиент) - Верификация: ~50 строк серверного кода
- Клиент: Web Component
<altcha-widget>или программный API - Лицензия: MIT
ALTCHA vs Cloudflare Turnstile
ALTCHA Turnstile Хостинг Self-hosted Cloudflare GDPR Полный контроль Данные у Cloudflare Стоимость Бесплатно Бесплатно Стойкость Средняя (PoW) Средняя-высокая (ML) Офлайн Работает Нет
Реализация
Клиент — Web Worker для неблокирующего решения:
// В Web Worker
self.onmessage = ({ data: { challenge, difficulty } }) => {
let nonce = 0
while (true) {
const hash = sha256(challenge + nonce)
if (hash.startsWith('0'.repeat(difficulty))) {
self.postMessage({ nonce, hash })
return
}
nonce++
}
}Сервер — верификация:
app.addHook('onRequest', (req, reply, done) => {
const solution = req.headers['x-pow-solution']
const challenge = req.headers['x-pow-challenge']
if (!verifyPoW(challenge, solution)) {
return reply.code(403).send({ error: 'Invalid proof of work' })
}
done()
})Когда применять
PoW добавляет 100-500ms задержку — не на каждый запрос. Стратегии:
| Стратегия | Когда PoW |
|---|---|
| Только публичные списки | GET без авторизации |
| Adaptive | При suspicion score > порога |
| Первый запрос в сессии | Один раз, потом cookie на 15 мин |
| Пагинация за N-й страницей | offset > 100 |
Для авторизованных пользователей — не нужен (они уже доказали, что не боты).
Ограничения
- Задержка 100-500ms ощутима для UX (хотя и в фоне)
- Web Worker не работает в IE11 (но уже неактуально)
- Бот-ферма с GPU может решать PoW быстрее — сложность нужно калибровать
- Не защищает от headless Chrome (он решает PoW как обычный браузер)
Связанные заметки
- Защита API от скрейпинга — общая стратегия
- HMAC-подпись API запросов — подпись запросов (дополняет PoW)
- Поведенческий анализ трафика — adaptive PoW при высоком suspicion score