Back to "StyloBot: Semplice quanto possibile e niente più semplice (Parte 3)"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

Architecture ASP.NET Bot Detection Security

StyloBot: Semplice quanto possibile e niente più semplice (Parte 3)

Monday, 16 February 2026

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

NuGet GitHub Docker



L'idea

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 .


Due linee di codice

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?

  • Dettatori 21 registrati: Assegnazione del modello dell'agente d'utente, coerenza del carattere da testareM SK2 rilevamento dei datacenter IP , analisi comportamentaleMska4 impronte digitali TLS MSC5JAMske6JA~4), TCPMsko8 impronti digitali IPMsku9 HTTPMsek10 impronta digitaleMMK11 analisi del comportamento del cacheMNK12 feedback sul comportamento di rispostaMKK13 multiMZK14 correlazioni stratificheMGK15 e piùMRK16
  • Pipeline basati su Wave-: I rilevatori funzionano in onde di dipendenza. La onda 0 (no dipendenzeM SK4 si esegue in paralleloMSC5 Le onde più tardi si attivano solo quando i segnali precedenti meritano un'analisi più approfonditaMNK6
  • Lo stoccaggio di SQLite: A botdetection.db file auto- crea modelli e pesci imparati. Niente configurazioneM SK2
  • Nella ricerca di somiglianza del processo in-: Indice dell'HNSW per trovare signature simili a quelle di un bot. Niente database di vettori esterniM SK2
  • Il punteggio heuristico: ~50 caratteristiche estrattoe per richiesta, valutate da un modello di processo leggeroM SK3

Tutto 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.


Bloccare tutti i bots, App intera

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


Minimale API: Esempio completo

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 .

I tipi di bot che si possono permettere

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

Controlli MVC: Attribute

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();

Gli Attribute

[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%" });
}

Il blocco del network geografico &

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();

Oltre il blocco/Allow: politiche di azione

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

appsettings.json

{
  "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
      }
    }
  }
}

Assignare politiche a punti finali

// 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.


Quello che si ottiene gratuitamente

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


Filtrazione basata sul segnale-

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

Minimale API

// 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");

MVC

[BlockIfSignal(SignalKeys.GeoIsVpn, SignalOperator.Equals, "True")]
public IActionResult Payment() => Ok();

[RequireSignal(SignalKeys.GeoCountryCode, SignalOperator.Equals, "US")]
public IActionResult DomesticOnly() => Ok();

Leggere segnali in linea

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..


Lo stiamo testando.

# 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.


Come Scala: Da File a Full Stack

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 .

Niveau 1: PersonaleM SK1Contante (Dove si inizia)

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

Niveau 2: Add GeoDetection

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.

Niveau 3: PostgreSQL + TimescaleDB

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 .

Tiero 4: Stazione completa - Portata SSK2 Qdrant + LLM

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

Ciò che ogni componente aggiunge

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.

Selezionare il vostro Tier

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


Enterprise Hooks

Il setup delle due linee è il punto di partenza.

Header di risposta per la debugging

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

Politiche di sfida (Frizione prima del blocco)

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();

IP Allow/Deny Lists

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

Metrica OpenTelemetry

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

Defaults di Route Group

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().

Politiche chiamate su Minimal API

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);

L'API di Feedback

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

Il confine di fiducia della Gateway con la firma dell'HMAC

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 SK2
  • X-Bot-Detection-Timestamp (Sekunden dell'Epoche UnitaM SK1 UTC)

Firma del contratto:

  • payload = X-Bot-Detected + ":" + X-Bot-Confidence + ":" + X-Bot-Detection-Timestamp
  • signature = 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:

  • Assicuratevi che la backend non sia pubblicamente accessibile (Docker internal networkM SK1 Kubernetes ClusterIP)
  • Sfrecciare X-Bot-* i titoli al vostro proxy di bordo prima che raggiungano la porta.
  • Usare la firma HMAC per la difesa-in- profondità anche con l'isolamento della rete

Quello che StyloBot non è

Worth being explicit:

  • Non WAF. StyloBot non inspecta la carica di carico per l'injezione SQL o XSS. Identifica Chi? sta facendo la richiesta, non Che cosa? Lo usate insieme ad un WAF.
  • Non una fattoria CAPTCHA. Le politiche di sfida esistono, ma la filosofia del design è la detezione-firstM SK2 L'obiettivo è sapere cosa si sta trattando. prima. Decidere se sfidare.
  • Non perimetro-soloM SK1 La rilevazione si fa a per-endpoint con per -end point policies. Potete avere /products permettere ai motori di ricerca mentre /api/checkout Ha bisogno di umani. Questa è la semantica del punto finale, non le regole del firewallM SK2
  • Non nuvole-dipendente. Tutto funziona da solo-contenuto. QdrantM SK2 TimescaleDB , LLM MST4 tutto opzionaleMSC5 Il nucleo è composto da due linee di codice e da un file SQLite
  • Incertezza-aware. Due punteggi indipendenti (probabilità +confidenzaM SK2 significa che si può distinguere |"probabilmente un robot | , noi |'non siamo sicuri | " | da |M"probablemente un bot | МSK8 | ma noi ' | ci diamo un'ipotesi |m". | La maggior parte dei sistemi ti danno un numero e la speranza per il migliore |

Cosa's successivo

La 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:

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.