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

*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](https://www.mostlylucid.net/blog/botdetection-introduction)**

**[Leggere la parte 2: Come i bot sono diventati più intelligenti](https://www.mostlylucid.net/blog/botdetection-part2-signature-pipeline-and-stylobot-architecture)**

**[👉 See It Live: StyloBotM SK2net](https://stylobot.net)** - Il sistema di produzione reale in funzione presto-Detezione dell'exit inline alla portaM SK2

<!--category-- ASP.NET, Bot Detection, Security, Architecture -->
<datetime class="hidden">2026-02-16T10:30</datetime>

[![NuGet](https://img.shields.io/nuget/v/mostlylucid.botdetection.svg)](https://www.nuget.org/packages/mostlylucid.botdetection/)
[![GitHub](https://img.shields.io/github/stars/scottgal/stylobot?style=social)](https://github.com/scottgal/stylobot)
[![Docker](https://img.shields.io/docker/pulls/scottgal/stylobot-gateway)](https://hub.docker.com/r/scottgal/stylobot-gateway)

---


[TOC]

---


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

```csharp
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:

```csharp
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

```json
{
  "BotDetection": {
    "BlockDetectedBots": true
  }
}
```

Che 's itM SK1 I robot rilevati sopra il tuo blocco - soglia di fiducia ottengono un`MinConfidenceToBlock` 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:

```csharp
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`:

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

```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddBotDetection();
builder.Services.AddControllersWithViews();

var app = builder.Build();
app.UseBotDetection();
app.MapControllers();
app.Run();
```

### Gli Attribute

```csharp
[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.

```csharp
// 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

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

```csharp
// 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.](https://github.com/scottgal/LLMApi/blob/main/Mostlylucid.BotDetection/docs/action-policies.md) 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`:

```csharp
// 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

```csharp
// 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

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

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

### Leggere segnali in linea

```csharp
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.](https://github.com/scottgal/LLMApi/blob/main/Mostlylucid.BotDetection/docs/signals-and-custom-filters.md).

---


## Lo stiamo testando.

```bash
# 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:

```csharp
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](https://en.wikipedia.org/wiki/Geolocation_software#IP_address) e [DataHub GeoIP dataset](https://datahub.io/core/geoip2-ipv4) 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](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data/).

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](https://docs.timescale.com/) (a estensione PostgreSQL per il tempo-dati di serieM SK2 per l'analisi

```csharp
builder.Services.AddBotDetection();
builder.Services.AddStyloBotDashboard();
builder.Services.AddStyloBotPostgreSQL(connectionString, options =>
{
    options.EnableTimescaleDB = true;
    options.RetentionDays = 90;
    options.CompressionAfter = TimeSpan.FromDays(7);
});
```

```yaml
# 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](https://en.wikipedia.org/wiki/Reverse_proxy) che si trova davanti alla vostra app e aggiunge sicurezza/Logica del traffico."

```yaml
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:

```csharp
// ASP.NET Core
builder.Services.Configure<BotDetectionOptions>(o => o.TrustUpstreamDetection = true);
```

O leggere i titoli direttamente in qualsiasi lingua:

```python
# 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')
```

```javascript
// 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:

```json
{
  "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

```json
{
  "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]`:

```csharp
[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](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) ranges:

```json
{
  "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](https://opentelemetry.io/docs/), [Prometheus](https://prometheus.io/docs/introduction/overview/), [Grafana](https://grafana.com/docs/), e qualsiasi .NET metrico consumatoreM SK2

```csharp
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:

```csharp
// 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:

```csharp
// 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`:

```bash
# 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):**

```json
{
  "BotDetection": {
    "TrustUpstreamDetection": true
  }
}
```

**HMAC-confidenza firmata M SK1verificazione criptografica):**

```json
{
  "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](https://datatracker.ietf.org/doc/html/rfc2104) 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:**

- NuGet: `dotnet add package Mostlylucid.BotDetection`
- Gateway Docker: `docker pull scottgal/stylobot-gateway`
- [Documenti completi](https://github.com/scottgal/LLMApi/tree/main/Mostlylucid.BotDetection/docs)
- [Live demo: StyloBot.net](https://stylobot.net)