La detezione dei robot per l'impresa non dovrebbe'dure un dottorato in infrastrutture (o migliaia al mese di spese per usarlo !). Due linee di codiceM SK3 zero servizi esterniMNK4 e voiMMK5lavorate SSK6~) \21\detttori in millisecondi su ogni richiesta a ogni punto di fineMRK9
Leggere la parte 1: StyloBot: Combattersi di nuovo contro i Combattenti
Leggere la parte 2: Come i bot sono diventati più intelligenti
👉 See It Live: StyloBotM SK2net - Il sistema di produzione reale in funzione presto-Detezione dell'exit inline alla portaM SK2
Einstein diceva:,, ", "Tutto deve essere fatto il più semplice possibile, ,, ma niente di più semplice,."", "Questo è il principio di design del StyloBot, il modello di integrazione del ', il .".
Parte 1 e 2 coperte Perché? i problemi di rilevamento dei robot e Come funziona il tubo di rilevamento?. Questo post copre Quanti piccoli codici ci servono? - e come lo stesso sistema scala da una sola app di file - ad un'intera porta di produzione con TimescaleDB, La ricerca dei vectori QdrantM SK3 e il processore CPUMSC4 Solo classificazione LLMMスク5
Il punto di vista chiave: Ogni livello usa la stessa catena di rilevamento.. Voi' non cambiate i schemi mentre cresceteM SK2 Vogliamo aggiungere l'archiviazione e l'enrichimento intorno allo stesso nucleo .
Questo è il minimo assoluto. Nessun file di configurazione, nessuna configurazione della base di datiM SK2 nessuna chiave API , nessun contenitore DockerMSC4
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBotDetection(); // ← that's line 1
var app = builder.Build();
app.UseBotDetection(); // ← that's line 2
app.Run();
Cos'è successo?
botdetection.db file auto- crea modelli e pesci imparati. Niente configurazioneM SK2Tutto questo va avanti. sotto 1 millisecondi per ogni richiesta di hardware di merce. solo CPU, nessun GPUM SK2
Ogni richiesta ora ha risultati di rilevamento disponibili tramite HttpContext Prolungamenti:
app.MapGet("/", (HttpContext ctx) => Results.Ok(new
{
isBot = ctx.IsBot(),
probability = ctx.GetBotProbability(), // 0.0-1.0: how likely it's a bot
confidence = ctx.GetDetectionConfidence(), // 0.0-1.0: how certain the system is
type = ctx.GetBotType()?.ToString(),
name = ctx.GetBotName()
}));
La rilevazione funziona ma niente blocca. Decidete cosa fare con i risultati.
Se volete solo bloccare i bot dall'intera vostra applicazione - nessun perM SK1config punto di fine, nessun attributo - èMSC4 una linea di JSONMST5
{
"BotDetection": {
"BlockDetectedBots": true
}
}
Che 's itM SK1 I robot rilevati sopra il tuo blocco - soglia di fiducia ottengono unMinConfidenceToBlock defaults to 0.8). I motori di ricerca (Googlebot, Bing botM SK3 le preview dei social media ♫(FacebookMST5 TwitterMSC6XMSST7 e i robot di monitoraggio |(UptimeRobot | MST9 | Pingdom | SST10 | sono accessibili da default |SST11 | perché quasi certamente li volete |
O la stessa cosa nel codice, non c'è bisogno di file di configurazione:
builder.Services.Configure<BotDetectionOptions>(o =>
{
o.BlockDetectedBots = true;
o.MinConfidenceToBlock = 0.8; // only block when confident
o.AllowVerifiedSearchEngines = true; // Googlebot, Bingbot through
o.AllowSocialMediaBots = true; // Facebook, Twitter previews through
o.AllowMonitoringBots = true; // UptimeRobot, Pingdom through
});
Questo è il "Io non lo voglio 'non voglio pensarci"modoM SK3Funzionano le rilevazioniMSC4 i robot vengono bloccatiMST5 bravi crawler passano attraversoMst6 Si muovo a perMSt7controllo finale quando ti serveM st8
Qui ' è un intero , API di lavoro con per- protezione dei bot terminaliM SK3 Questo è l'intero Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBotDetection();
var app = builder.Build();
app.UseBotDetection();
// Detection results available, no blocking
app.MapGet("/", (HttpContext ctx) => Results.Ok(new
{
isBot = ctx.IsBot(),
probability = ctx.GetBotProbability(),
confidence = ctx.GetDetectionConfidence(),
type = ctx.GetBotType()?.ToString(),
name = ctx.GetBotName()
}));
// Block all bots
app.MapGet("/api/data", () => Results.Ok(new { data = "sensitive" }))
.BlockBots();
// Allow search engines (Googlebot, Bingbot, Yandex)
app.MapGet("/products", () => Results.Ok(new { catalog = "public" }))
.BlockBots(allowSearchEngines: true);
// Allow search engines + social media previews (Facebook, Twitter/X)
app.MapGet("/blog/{slug}", (string slug) => Results.Ok(new { post = slug }))
.BlockBots(allowSearchEngines: true, allowSocialMediaBots: true);
// Health check: monitoring bots allowed (UptimeRobot, Pingdom)
app.MapGet("/health", () => Results.Ok("healthy"))
.BlockBots(allowMonitoringBots: true);
// Humans only - blocks ALL bots including verified crawlers
app.MapPost("/api/submit", () => Results.Ok(new { submitted = true }))
.RequireHuman();
// High-confidence blocking only (reduces false positives)
app.MapGet("/api/lenient", () => Results.Ok("data"))
.BlockBots(minConfidence: 0.9);
// Geo + network blocking (needs GeoDetection contributor)
app.MapPost("/api/payment", () => Results.Ok("ok"))
.BlockBots(blockCountries: "CN,RU", blockVpn: true, blockDatacenter: true);
// Honeypot: deliberately allow scrapers in
app.MapGet("/honeypot", () => Results.Ok("welcome"))
.BlockBots(allowScrapers: true, allowMaliciousBots: true);
// Dev diagnostics
app.MapBotDetectionEndpoints();
app.Run();
Ogni anno. .BlockBots() blocchi di chiamata Tutti. I tipi di bot per default. Si possono scegliere tipi specifici. Si tratta di un sistema basato su una classificazione basata sulla classificazione. con l'uso di Allow* Parameteri. L'idea è negare-dall'altra parteM SK2defaultMSC3 lista bianca le buone .
| Parametro | Cosa lo consente | Perché lo usate' |
|---|---|---|
allowSearchEngines |
Googlebot, Bingbot , Yandex | SEO SSK4 volete essere inseriti in un'indexazione S |
allowSocialMediaBots |
FacebookM SK1 Twitter/XMSC3 LinkedIn | Previews di linkMST5 Open Graph cards |
allowMonitoringBots |
UptimeRobotM SK1 Pingdom, StatusCake | Controlli di saluteMSC4 Monitoring dell'approvvigionamento. |
allowAiBots |
GPTBotM SK1 ClaudeBot, GoogleMSC3Extended | Opt-in to AI training |
allowGoodBots |
Reader per il feedM SK1 Checker per i link | Automatizzazione dei Benign |
allowVerifiedBots |
DNS | |
allowScrapers |
AhrefsBot, SemrushBot | Honeypots |
allowMaliciousBots |
I cattivi attori conosciuti | Honeypots |
minConfidence |
(intervalloM SK1 | Bloccare solo quando il sistema è molto sicuro |
La stessa catena di rilevamento, protezione tramite attributi.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBotDetection();
builder.Services.AddControllersWithViews();
var app = builder.Build();
app.UseBotDetection();
app.MapControllers();
app.Run();
[ApiController]
[Route("[controller]")]
public class ProductsController : ControllerBase
{
// No protection - detection runs but nothing blocks
[HttpGet]
public IActionResult List() => Ok(new { products = "all" });
// Block all bots, allow search engines
[HttpGet("catalog")]
[BlockBots(AllowSearchEngines = true)]
public IActionResult Catalog() => Ok(new { catalog = "indexed" });
// Block all bots, allow search engines + social previews
[HttpGet("{id:int}")]
[BlockBots(AllowSearchEngines = true, AllowSocialMediaBots = true)]
public IActionResult Detail(int id) => Ok(new { id });
}
// Entire controller: humans only
[ApiController]
[Route("[controller]")]
[RequireHuman]
public class CheckoutController : ControllerBase
{
[HttpPost("cart")]
public IActionResult AddToCart() => Ok();
[HttpPost("pay")]
public IActionResult Pay() => Ok();
}
// Infrastructure endpoints
[ApiController]
[Route("[controller]")]
public class InfraController : ControllerBase
{
// Skip detection entirely
[HttpGet("health")]
[SkipBotDetection]
public IActionResult Health() => Ok("ok");
// Monitoring bots allowed
[HttpGet("status")]
[BlockBots(AllowMonitoringBots = true)]
public IActionResult Status() => Ok(new { uptime = "99.9%" });
}
Questi lavorino sia su attributi MVC che su filtri API Minimal. Richiedono il contribuente GeoDetection per i dati del segnale.
// Block countries
[BlockBots(BlockCountries = "CN,RU,KP")]
public IActionResult SensitiveApi() => Ok();
// Country whitelist - only these allowed
[BlockBots(AllowCountries = "US,GB,DE,FR")]
public IActionResult DomesticOnly() => Ok();
// Block VPNs + proxies (anti-fraud)
[BlockBots(BlockVpn = true, BlockProxy = true)]
public IActionResult Payment() => Ok();
// Block datacenter IPs + Tor
[BlockBots(BlockDatacenter = true, BlockTor = true)]
public IActionResult FormSubmission() => Ok();
// Combine: SEO-friendly + geo block + VPN block
[BlockBots(AllowSearchEngines = true, BlockCountries = "CN,RU", BlockVpn = true)]
public IActionResult ProtectedContent() => Ok();
Blocco binario/autorizzare è semplice ma limitato. Politiche di azione separate Quello che si rileva a partire da Come reagi?. Definire le strategie di risposta nella configurazione, assegnarle ai punti finaliM SK2
{
"BotDetection": {
"BotThreshold": 0.7,
"ActionPolicies": {
"api-block": {
"Type": "Block",
"StatusCode": 403,
"Message": "Bot traffic is not allowed."
},
"api-throttle": {
"Type": "Throttle",
"BaseDelayMs": 500,
"MaxDelayMs": 5000,
"ScaleByRisk": true,
"JitterPercent": 0.3
},
"shadow-mode": {
"Type": "LogOnly",
"AddResponseHeaders": true,
"LogFullEvidence": true
}
}
}
}
// Bots get progressively slower responses (they don't know they're being throttled)
[BotPolicy("default", ActionPolicy = "api-throttle")]
public IActionResult Browse() => Ok();
// Hard block
[BotPolicy("default", ActionPolicy = "api-block")]
public IActionResult Confirm() => Ok();
// Shadow mode: log everything, block nothing (deploy first, tune later)
[BotPolicy("default", ActionPolicy = "shadow-mode")]
public IActionResult PublicApi() => Ok();
Cinque tipi di politica: Block (HTTP 403), Throttle (delitti di privacyM SK1 Challenge (CAPTCHA Redirect ( LogOnly (modo diombra). Vedete il Doc delle politiche di azione. per la descrizione completa.
Il modo "shadow" è il punto di partenza preferito. Detezione di deploiamento, Osservare i risultatiM SK2 soglia di tonalità e poi. iniziare a bloccare.
Ogni richiesta dopo. UseBotDetection() queste estensioni sono disponibili su HttpContext:
// Am I talking to a bot?
context.IsBot() // true if probability >= threshold
context.IsHuman() // inverse
context.IsSearchEngineBot() // Googlebot, Bingbot, etc.
context.IsVerifiedBot() // DNS-verified bots
context.IsMaliciousBot() // known bad actors
// How bad is it?
context.GetBotProbability() // 0.0-1.0: likelihood of being a bot
context.GetDetectionConfidence() // 0.0-1.0: how certain the system is
context.GetRiskBand() // Low, Elevated, Medium, High
context.GetRecommendedAction() // Allow, Challenge, Throttle, Block
// What is it?
context.GetBotType() // BotType enum
context.GetBotName() // "Googlebot", "Scrapy", etc.
// Full breakdown
var result = context.GetBotDetectionResult();
Due punteggi indipendenti sono importanti qui: Probabilità di bot (come è probabile che questo sia un robot?) e La fiducia nella rilevazione. (come si è certi del sistema?). Potete essere 95% sicuri che qualcosa sia. l'uomo. (poche probabilitàM SK1alta fiducia). Oppure potete vedere una richiesta sospetta ma con poca fiducia perché c'è solo un rilevatore in funzioneMSC3
Oltre i tipi di bot, StyloBot espone segnali tipizzati 100+ dai suoi rilevatoriM SK2 Si possono filtrare punti finali basati su valori specifici del segnale - sia per la Minimal API che per il MVC
// Block VPN traffic
app.MapPost("/api/payment", () => Results.Ok())
.BlockIfSignal(SignalKeys.GeoIsVpn, SignalOperator.Equals, "True");
// Block datacenter IPs
app.MapPost("/api/submit", () => Results.Ok())
.BlockIfSignal(SignalKeys.IpIsDatacenter, SignalOperator.Equals, "True");
// Only allow US traffic
app.MapGet("/api/domestic", () => Results.Ok())
.RequireSignal(SignalKeys.GeoCountryCode, SignalOperator.Equals, "US");
// Block high-confidence bots by heuristic score
app.MapGet("/api/premium", () => Results.Ok())
.BlockIfSignal(SignalKeys.HeuristicConfidence, SignalOperator.GreaterThan, "0.9");
[BlockIfSignal(SignalKeys.GeoIsVpn, SignalOperator.Equals, "True")]
public IActionResult Payment() => Ok();
[RequireSignal(SignalKeys.GeoCountryCode, SignalOperator.Equals, "US")]
public IActionResult DomesticOnly() => Ok();
app.MapGet("/debug", (HttpContext ctx) =>
{
var country = ctx.GetSignal<string>(SignalKeys.GeoCountryCode);
var isVpn = ctx.GetSignal<bool>(SignalKeys.GeoIsVpn);
var isDc = ctx.IsDatacenter();
var heuristic = ctx.GetSignal<double>(SignalKeys.HeuristicConfidence);
return Results.Ok(new { country, isVpn, isDc, heuristic });
});
Referenza completa al segnale: segnali e filtri personalizzati..
# Normal browser request → low bot score
curl -H "Accept: text/html" -H "Accept-Language: en-US" \
-A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0" \
http://localhost:5090/
# Googlebot → allowed where AllowSearchEngines=true
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
http://localhost:5090/products
# Scraper → blocked by .BlockBots()
curl -A "Scrapy/2.7" http://localhost:5090/api/data
# Full detection breakdown → shows all signals and per-detector contributions
curl http://localhost:5090/bot-detection/check
# Simulate bot types via test mode header
curl -H "ml-bot-test-mode: malicious" http://localhost:5090/bot-detection/check
curl -H "ml-bot-test-mode: scraper" http://localhost:5090/api/data
L'informazione figura nella parte dispositiva. /bot-detection/check il punto finale è il vostro amico di sviluppo. Rende ogni segnale da ogni rilevatore, dati di timingM SK2 e per i contributi dei rilevatori, così che possiate vedere esattamente cosa sta succedendo.
Questo è il principio di progettazione più importante: Ogni livello usa la stessa catena di rilevamento.. Voi' non riscrivete mai il codice di protezioneM SK2 Voi' aggiungete l'infrastruttura intorno allo stesso nocciolo .
Your App + AddBotDetection()
└── SQLite (auto-created botdetection.db)
└── In-process [HNSW](https://en.wikipedia.org/wiki/Hierarchical_navigable_small_world_graphs) similarity search
└── 21 detectors, <1ms per request
└── No external services
Tutti i rilevatori 21 funzionano in una onda-in un tubo basatoM SK2FastMSC3dettatori di percorso (UserAgentMska5HeaderMske6IPMsek7ConduttiviMске8Taglio digitale TLSM Ske9Si eseguiscono in parallelo nella Wave CMS10Estrazioni heuristice di punteggio DMS11Feature e conduce un modello di punteggi leggeriMS.Patterni imparati persistono su SQLite attraverso i ristartsMSSK13Se volete degli interniM,Parte |2 copre l'architettura e il flusso dei segnali in dettaglioMSSK16
Benissimo per: App unica, M SK1K richieste/ giornoMSC3 inizioMST4
Add geo routing plus the geo contributor:
builder.Services.AddBotDetection();
builder.Services.AddGeoRoutingWithDataHub(); // free local GeoIP DB (no account)
builder.Services.AddGeoDetectionContributor(options =>
{
options.FlagVpnIps = true;
options.FlagHostingIps = true;
});
Se la geolocalizzazione IP è nuova: Il background di GeoIP e DataHub GeoIP dataset sono buoni punti di partenza. DataHubCsv scarica una free ~27MB IP database al primo lancio e la mantiene aggiornata settimanalmenteM SK2 Tutte le visite sono locali - nessun perMSC4 richiede chiamate HTTPMST5 Per la cittàMSP6 precisione di livelloMSV7 uso MaxMind GeoLite2.
Ora si ottengono 20+ segnali geo ( paese, VPNM SK3 proxyMST4 TorMSC5 rilevamento del centro di datiMSSK6 e verifica dell'origine dei bot ♫( Googlebot da un centro di informazioni cinese ♫ = sospetto ♫ BlockCountries, BlockVpn, BlockDatacenter, BlockTor i parametri si attivano.
Sostituire SQLite con PostgreSQL per l'apprendimento condiviso multi-server e aggiungere TimescaleDB (a estensione PostgreSQL per il tempo-dati di serieM SK2 per l'analisi
builder.Services.AddBotDetection();
builder.Services.AddStyloBotDashboard();
builder.Services.AddStyloBotPostgreSQL(connectionString, options =>
{
options.EnableTimescaleDB = true;
options.RetentionDays = 90;
options.CompressionAfter = TimeSpan.FromDays(7);
});
# docker-compose.yml
services:
timescaledb:
image: timescale/timescaledb:latest-pg16
environment:
POSTGRES_DB: stylobot
POSTGRES_USER: stylobot
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- timescale-data:/var/lib/postgresql/data
app:
build: .
environment:
ConnectionStrings__BotDetection: "Host=timescaledb;Database=stylobot;Username=stylobot;Password=${DB_PASSWORD}"
depends_on:
timescaledb:
condition: service_healthy
TimescaleDB vi dà la partizione ipertabile, compressione automatica M SK1 riduzione di memoria dopo 7 giorni), aggregi continui per il sotto--questioni da scatola millisecondiMST5 e politiche di conservazioneMSC6
Benissimo per: >100K richiesteM SK1 giorno, server multipleMSC3 dashboard di analisi necessarie .
Internet → Caddy (TLS) → Stylobot Gateway ([YARP](https://microsoft.github.io/reverse-proxy/)) → Your App
│
├── TimescaleDB (analytics, learning)
├── [Qdrant](https://qdrant.tech/documentation/) (vector similarity search)
└── LLamaSharp CPU [LLM](https://en.wikipedia.org/wiki/Large_language_model) (bot classification)
La porta è un contenitore Docker autonomo (scottgal/stylobot-gateway) che fa la rilevazione su tutti i traffici e trasmette i risultati come titoli HTTP. La vostra app legge i titoli - non c'è bisogno di SDK, nessuna lingua. Se "gateway" è sconosciutoM SK3 pensate "Proxy inversa che si trova davanti alla vostra app e aggiunge sicurezza/Logica del traffico."
services:
gateway:
image: scottgal/stylobot-gateway:latest
environment:
DEFAULT_UPSTREAM: "http://app:8080"
StyloBotDashboard__PostgreSQL__ConnectionString: "Host=timescaledb;..."
StyloBotDashboard__PostgreSQL__EnableTimescaleDB: true
BotDetection__Qdrant__Enabled: true
BotDetection__Qdrant__Endpoint: http://qdrant:6334
BotDetection__Qdrant__EnableEmbeddings: true
BotDetection__AiDetection__Provider: LlamaSharp
BotDetection__AiDetection__LlamaSharp__ModelPath: "Qwen/Qwen2.5-0.5B-Instruct-GGUF/qwen2.5-0.5b-instruct-q4_k_m.gguf"
app:
build: .
environment:
BOTDETECTION_TRUST_UPSTREAM: true
qdrant:
image: qdrant/qdrant:latest
timescaledb:
image: timescale/timescaledb:latest-pg16
caddy:
image: caddy:latest
La vostra app crede al gateway's headers:
// ASP.NET Core
builder.Services.Configure<BotDetectionOptions>(o => o.TrustUpstreamDetection = true);
O leggere i titoli direttamente in qualsiasi lingua:
# Python/Flask
@app.route('/api/data')
def api_data():
if request.headers.get('X-Bot-Detected') == 'true':
return jsonify(error='blocked'), 403
return jsonify(data='sensitive')
// Node.js/Express
app.get('/api/data', (req, res) => {
if (req.headers['x-bot-detected'] === 'true') {
return res.status(403).json({ error: 'blocked' });
}
res.json({ data: 'sensitive' });
});
Header che il gateway manda:
| Insieme | Esempio | Obiettivo S |
|---|---|---|
X-Bot-Detected |
true |
BotM SK1 classificazione umana |
X-Bot-Confidence |
0.91 |
Confidenza di rilevamento |
X-Bot-Detection-Probability |
0.87 |
Probabilità del bot |
X-Bot-Type |
Scraper |
Categoria dei bot |
X-Bot-Name |
AhrefsBot |
Bot identificato |
X-Bot-Detection-RiskBand |
High |
Classificazione dei rischi |
| Componente | ||
|---|---|---|
| TimescaleDB | TempoM SK1analisi di serie, immagazzinamento compressoMNK3 aggregati continuiMMK4 politiche di conservazione | Suggerito per la produzione SNK6 |
| Qdrant | La ricerca di somiglianza con i vettori - trova dei robot anche quando ruotano Usatore-Agenti ♫ | Opzionale ♫ |
| LLamaSharp | CPU-solo LLM per la classificazione e l'innomenazione dei gruppi di bot. | |
| Caddy/Nginx | Terminazione del TLS, file statici | il vostro proxy inversa |
| Portatile | Detezione centralizzata per multiapp o non--.NET backends. |
Starting out?
├── Single ASP.NET app → Tier 1 (two lines of code)
│ └── Need geo blocking? → Tier 2 (one more line)
│ └── Need analytics? → Tier 3 (add PostgreSQL)
└── Multiple apps or non-.NET? → Tier 4 (Gateway)
Il spostamento tra i livelli è un cambiamento di registro DI. Il codice di protezione del vostro punto di fine - il [BlockBots] attributes, il .BlockBots() filtri, il context.IsBot() Controlli - rimane esattamente ugualeM SK1
Il setup delle due linee è il punto di partenza.
Spegnere globalmente i titoli di rilevamento così da poter verificare il comportamento senza colpire i punti di fine diagnostici:
{
"BotDetection": {
"ResponseHeaders": {
"Enabled": true,
"HeaderPrefix": "X-Bot-",
"IncludeConfidence": true,
"IncludeDetectors": true,
"IncludeProcessingTime": true,
"SkipPaths": ["/health"]
}
}
}
Ogni risposta arriva. X-Bot-Detected, X-Bot-Confidence, X-Bot-Processing-Ms, etc. Utilizzabile per le decisioni di routing delle aree in Caddy /NginxM SK3 e per il debugging nel devMSC4 Disable nella produzione o restringersi a reti affidabiliMスク5
Don' non blocca l'incertezza M SK1 sfida invece . StyloBot ha cinque tipi di sfida
{
"BotDetection": {
"ActionPolicies": {
"challenge-on-uncertain": {
"Type": "Challenge",
"ChallengeType": "JavaScript"
},
"captcha-gate": {
"Type": "Challenge",
"ChallengeType": "Captcha",
"RedirectUrl": "/captcha"
},
"proof-of-work": {
"Type": "Challenge",
"ChallengeType": "ProofOfWork"
}
}
}
}
Tipi di sfida: Redirect ( mandare alla pagina di sfidaM SK1 Inline (HTML interstitiale), JavaScript (Protocolo JSM SK1di-operaMSC3 Captcha, ProofOfWork (questo di calcolo). Assignare ai punti finali attraverso [BotPolicy]:
[BotPolicy("default", ActionPolicy = "challenge-on-uncertain")]
public IActionResult Submit() => Ok();
Liste globali per consentire e negare i dati IP conosciuti. CIDR ranges:
{
"BotDetection": {
"WhitelistedIps": ["203.0.113.10/32", "198.51.100.0/24"],
"BlacklistedIps": ["1.2.3.4", "5.6.7.0/24"]
}
}
IP in lista bianca scorrono completamente la rilevazione. IP in Lista nera vengono bloccate immediatamente. Entrambi supportano la notazione CIDRM SK2
StyloBot espone le misurazioni attraverso System.Diagnostics.Metrics, compatibile con OpenTelemetry, Prometheus, Grafana, e qualsiasi .NET metrico consumatoreM SK2
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics.AddMeter("Mostlylucid.BotDetection"));
Metriki disponibili:
| Metrica | Tipo | Cosa misura S |
|---|---|---|
botdetection.requests.total |
Contatore | Il totale delle richieste processate |
botdetection.bots.detected |
Contatore | Requiste classificate come robot |
botdetection.humans.detected |
Contriuttore | Requiste classificate come umani |
botdetection.errors.total |
Contatore | Errori del tubo di detezione PSK2 |
botdetection.detection.duration |
Histogramma | La latenza di detezione SSK2ms) MSC4 |
botdetection.confidence.average |
Gauge | Confidenza media di giro MSC2 |
botdetection.cache.patterns.count |
Gauge | Numero di schemi codificati PSK2 |
Questi sono i numeri di cui avete bisogno per il pannello di controllo, l'allarmeM SK1 e la pianificazione della capacità. L'histogramma della latenza di rilevamento vi permette di stabilire gli SLO . il bot*/ i contatori umani vi danno la composizione del traffico nel tempoMSC5
Applicate la protezione dei robot su interi gruppi di corsie invece che ripetere per -endpoint:
// All /api routes: block bots, allow search engines
var api = app.MapGroup("/api").WithBotProtection(allowSearchEngines: true);
api.MapGet("/products", () => "data");
api.MapGet("/categories", () => "cats");
// Secured routes: humans only
var secure = app.MapGroup("/secure").WithHumanOnly();
secure.MapPost("/submit", () => "ok");
secure.MapPost("/checkout", () => "done");
// Individual endpoints can still override
api.MapGet("/special", () => "overridden")
.BlockBots(allowSearchEngines: true, allowSocialMediaBots: true);
WithBotProtection() prende gli stessi parametri geo/network/confidence come .BlockBots(), ma intenzionalmente blocca sempre gli smascheratori e i bot maliziosi a livello di gruppo (no allowScrapers / allowMaliciousBots su gruppi). WithHumanOnly() è l'equivalente di un gruppo. .RequireHuman().
Usare .BotPolicy() per assegnare le politiche di azione chiamate ai punti di fine del Minimal API - la stessa cosa. [BotPolicy] Fa per MVC:
// Throttle bots on this endpoint
app.MapGet("/api/data", () => "sensitive")
.BotPolicy("default", actionPolicy: "api-throttle");
// Block with high-confidence threshold
app.MapPost("/api/submit", () => "ok")
.BotPolicy("strict", actionPolicy: "block", blockThreshold: 0.8);
Racconta false positivi e negativi al sistema tramite POST /bot-detection/feedback:
# Mark a detection as a false positive (bot detected but was actually human)
curl -X POST http://localhost:5090/bot-detection/feedback \
-H "Content-Type: application/json" \
-d '{"outcome": "Human", "notes": "Known partner integration"}'
# Mark a missed bot (human detected but was actually a bot)
curl -X POST http://localhost:5090/bot-detection/feedback \
-H "Content-Type: application/json" \
-d '{"outcome": "Bot", "notes": "Automated scraper spotted in logs"}'
Il punto finale restituisce se il feedback rappresenta un falso positivo o un falso negativo rispetto al risultato di rilevamento attuale. Questa è la base per l'apprendimento a circuito chiuso-loop2
Quando usate il gateway YARP, la vostra backend si affida ai header di rilevamento in arrivo. Questa è una configurazione sensibile per la sicurezzaM SK2 - dovete assicurarvi che solo il gateways può stabilire quei headersMSC4
Confidenza di base ( reteM SK1 isolamento a livello solo):
{
"BotDetection": {
"TrustUpstreamDetection": true
}
}
HMAC-confidenza firmata M SK1verificazione criptografica):
{
"BotDetection": {
"TrustUpstreamDetection": true,
"UpstreamSignatureHeader": "X-Bot-Signature",
"UpstreamSignatureSecret": "base64-encoded-shared-secret"
}
}
Quando? UpstreamSignatureHeader e UpstreamSignatureSecret sono stati stabiliti, il middleware verifica un HMAC-SHA256 firma prima di fidarsi dei titoli in arrivo.
Usate questo per ora. Gateway personalizzato/integrazioni proxy che aggiungono i titoli di firma. L'interfaccia di Stylobot costruita-in avanti porta il botM SK2header di rilevamentoMSC3 ma non emette ancora i titoli della firma HMAC .
Cose da scrivere firmate:
X-Bot-Signature (base64HMACM SK2X-Bot-Detection-Timestamp (Sekunden dell'Epoche UnitaM SK1 UTC)Firma del contratto:
payload = X-Bot-Detected + ":" + X-Bot-Confidence + ":" + X-Bot-Detection-Timestampsignature = Base64(HMACSHA256(payload, base64Decoded(UpstreamSignatureSecret)))Signature fuori da un 5-window di riproduzione di un minuto vengono rifiutate. Se la firma mancaM SK2invalidaMSC3 o che è finita , i header in arrivo sono rifiutati e la rilevazione locale completa viene attivata inveceMSL5
Importante: Spegnere la fiducia solo quando il vostro backend è dietro un proxy inversa affidabile. Se un attaccatore riesce a raggiungere il vostro Backend direttamente, può imitare. X-Bot-Detected: false e bypassare tutte le rilevazioni. In produzione:
X-Bot-* i titoli al vostro proxy di bordo prima che raggiungano la porta.Worth being explicit:
/products permettere ai motori di ricerca mentre /api/checkout Ha bisogno di umani. Questa è la semantica del punto finale, non le regole del firewallM SK2La parte 1 riguardava il perché la rilevazione dei robot è importante. La parte 2 riguardava l'interfaccia interna del tubo di rilevamentoM SK3 Questo posto ha riguardato l'integrazione minimamente sostenibile e il percorso di scalatura - da due linee di codice a una porta di produzione completaMSC5
Cominciamo:
dotnet add package Mostlylucid.BotDetectiondocker pull scottgal/stylobot-gateway© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.