feat(security): recovery alerts, gate-block sharing, rolling-window burst and admin breakdown for CrowdSec
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m50s
CI / tests-ui (push) Successful in 2m42s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m3s
Gitea Actions Runner Test / test-job (push) Successful in 1s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m50s
CI / tests-ui (push) Successful in 2m42s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m3s
This commit is contained in:
1 parent
301edd2c9a
commit
3e1a3f92c8
8 files changed
+448
-65
No files matched your search
@@ -8,6 +8,11 @@ import { resolveClientIp } from "@/lib/client-ip";
|
||||
import { isCloudflareProxied } from "@/lib/cloudflare";
|
||||
import { maybeAutoBlockCloudflare } from "@/lib/cloudflare-api";
|
||||
import { maybeAutoBlockCrowdsec } from "@/lib/crowdsec-api";
|
||||
import { reportCrowdsecSignal } from "@/lib/crowdsec-report";
|
||||
import {
|
||||
bumpCrowdsecBreakdownStat,
|
||||
bumpCrowdsecStat,
|
||||
} from "@/lib/crowdsec-stats";
|
||||
import { classifyDdos, isSuspiciousPath } from "@/lib/ddos";
|
||||
import { rateLimit } from "@/lib/rate-limit";
|
||||
import { redis } from "@/lib/redis";
|
||||
@@ -113,6 +118,36 @@ export async function enforceDdosRateLimit(
|
||||
const ttl = blockTtlForViolations(violations, config.blockTiers);
|
||||
if (violations >= config.maxViolations) {
|
||||
await redis.set(blockKey, "1", "EX", ttl);
|
||||
// Share the block in the daily activity histogram + breakdown.
|
||||
void bumpCrowdsecStat("blocks");
|
||||
void bumpCrowdsecBreakdownStat("category", category);
|
||||
// Opt-in: also push our OWN detection (not just CrowdSec-
|
||||
// reputation blocks) into the community blocklist via the same
|
||||
// CAPI channel. Fire-and-forget; deduped per IP internally.
|
||||
void reportCrowdsecSignal({
|
||||
ip,
|
||||
category,
|
||||
ttlSeconds: ttl,
|
||||
verdict: {
|
||||
ip,
|
||||
reputation: null,
|
||||
score: 0,
|
||||
aggressiveness: 0,
|
||||
confidence: null,
|
||||
behaviors: [`gate:${category}`],
|
||||
falsePositive: false,
|
||||
checkedAt: Date.now(),
|
||||
},
|
||||
meta: {
|
||||
source: "gate",
|
||||
category,
|
||||
reputation: null,
|
||||
score: 0,
|
||||
behaviors: [`gate:${category}`],
|
||||
ttlSeconds: ttl,
|
||||
blockedAt: Date.now(),
|
||||
},
|
||||
});
|
||||
// Mirror the host-level block to the Cloudflare edge (IP Access
|
||||
// Rules) so a repeat offender is shed before it reaches the
|
||||
// origin. Only when this request demonstrably transited
|
||||
|
||||
Reference in new issue
Block a user