Node CrowdSec Client
    Preparing search index...

    Module crowdsec-http-middleware - v0.1.1

    crowdsec-http-middleware

    NPM version CI codecov Downloads License Known Vulnerabilities

    Donate GitHub stars Package Quality

    Bugs Code Smells Duplicated Lines (%) Lines of Code Maintainability Rating Quality Gate Status Reliability Rating Security Rating Technical Debt Vulnerabilities

    Dependencies update - renovate

    NPM

    Protect your Node.js HTTP server with CrowdSec.

    This package runs a CrowdSec bouncer inside your app : it checks each incoming request's IP against CrowdSec's decisions and tells you — via req.decision — whether the visitor is banned, should be challenged with a captcha, or is clean. You decide the response (custom page, captcha, redirect, JSON...). A watcher can also detect malicious requests and report them to CrowdSec.

    Requires Node.js >= 24 and a CrowdSec LAPI.

    The simplest setup: install, configure the LAPI URL + a bouncer API key, and start.

    npm i crowdsec-http-middleware
    
    import * as http from 'http';
    import { CrowdSecHTTPMiddleware } from 'crowdsec-http-middleware';

    const middleware = new CrowdSecHTTPMiddleware({
    url: process.env.CROWDSEC_URL, // e.g. http://localhost:8080
    bouncer: {
    apiKey: process.env.CROWDSEC_API_KEY // from the LAPI bouncer config
    }
    });

    await middleware.start();

    const server = http.createServer((req, res) => {
    middleware.getMiddleware()(req, res);

    if (req.decision) {
    // banned or captcha : you decide what the visitor sees
    res.statusCode = 403;
    res.end('You are blocked by CrowdSec');
    return;
    }

    res.statusCode = 200;
    res.end('Hello, World!');
    });
    server.listen(3000);

    That's it. req.decision is undefined for clean visitors and holds the decision (ban, captcha...) for flagged ones.

    Need more control (live mode, which subnets to trust, a watcher, an AI agent to configure it) ? Read on.

    install it

    npm i crowdsec-http-middleware
    

    and then read the documentation in the wiki

    This package, support a default setup, with default scenarios . You can use the default mode by installing crowdsec-http-middleware and crowdsec-client-scenarios, and passing an empty scenarios configuration

    npm i crowdsec-http-middleware crowdsec-client-scenarios
    

    you can read what are the default scenarios enabled in crowdsec-client-scenarios

    This package, is a base package to create HTTP Middleware for HTTP Servers

    A full example, showing how you stay in control of the response (custom message per decision type) :

    import * as http from 'http';
    import { CrowdSecHTTPMiddleware } from 'crowdsec-http-middleware';

    // init the middleware (we will see the options later)
    const middleware = new CrowdSecHTTPMiddleware(middlewareOptions);
    //wait async stuff like connection to crowdsec LAPI
    await middleware.start();

    const server = http.createServer((req: IncomingMessage & { ip?: string; decision?: Decision }, res: ServerResponse) => {
    try {
    middleware.getMiddleware()(req, res);
    } catch (e) {
    console.error('middleware error', e);
    }

    if (!req.decision) {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello, World!');
    return;
    }

    res.statusCode = 403;
    res.setHeader('Content-Type', 'text/plain');
    res.end(`You can't access this api, because you are : ${req.decision?.type}`);
    });

    const port: number = 3000;
    server.listen(port, () => {
    console.log(`Server running at http://localhost:${port}/`);
    });

    options are described here : technical documentation

    Copy-paste this into your AI agent. It reads the setup guide and interviews you before writing the config.

    Help me configure the node-crowdsec HTTP middleware (bouncer and/or watcher,
    with optional scenarios).
    
    1. Read this guide: https://raw.githubusercontent.com/thib3113/node-crowdsec/main/docs/agent-setup-guide.md
    2. First tell me if I even need this library, then ask me the questions it lists.
    3. Use the recommended defaults when I have no opinion.
    4. Output the `CrowdSecHTTPMiddleware` config + a short justification.
    

    First the global options

    const middlewareOptions: ICrowdSecHTTPMiddlewareOptions = {
    // this is the url of the crowdsec instances
    url: process.env.CROWDSEC_URL,
    // options to pass to the crowdsec-client
    clientOptions: {
    // for example, to disable ssl certificate verification
    strictSSL: false
    },
    // here, an optional function to extract Ip from request
    // you can also use a scenario with "extractIp" capability
    // getCurrentIp is prior to scenarios extractIp . If you want to use a default function, create a scenario with only extractIp
    getCurrentIp: (req: IncomingMessage) => req.socket.remoteAddress || '0.0.0.0',
    //we will see this configurations later
    watcher: watcherOptions,
    bouncer: bouncerOptions
    }

    the watcher options allow you to setup an optional watcher . The watcher, will connect with crowdsec LAPI, and run scenarios to send alerts when analyzing requests

    you need to remember, that crowdSec is an IDS, it will detect the alert and block it the next time

    about authentication, you can also use TLS certificates . Check the wiki

    const watcherOptions = {
    machineID: 'myMachine',
    password: 'myPassword',
    // send heartbeat to LAPI ? it allow the LAPI to see the watcher "online"
    heartbeat: true,
    // a list of scenarios constructors that will be used
    scenarios: [],
    // options passed to the scenarions
    scenariosOptions: {}
    }

    you can read more about scenarios and scenarioOptions in the crowdsec-client-scenario package

    bouncer, will check if a decision is associated with the current IP .

    about authentication, you can also use TLS certificates . Check the wiki

    const bouncerOptions = {
    apiKey: process.env.CROWDSEC_API_KEY || '',
    // how often the bouncer pulls the decisions stream from the LAPI ( in ms )
    pollingInterval: 10000,
    // how far up the prefix hierarchy to consider as malicious.
    // "resident" = only /32, "company" = up to /24 ( default ), "country" = up to /16
    subnetLevel: SubnetLevel.company,
    // optional live mode : checks unknown ips against the LAPI in the background
    live: {
    // enable the live mode ( default : false )
    enabled: false,
    // what to do when a live check fails : failOpen ( default, cache the failure
    // for errorBackoffTtl) or failFast ( re-check on every request )
    errorBehavior: LiveCheckErrorBehavior.failOpen,
    // how long ( s ) a "clean" verdict is trusted before re-checking ( default : 60 )
    cleanCacheTtl: 60,
    // max number of "clean" verdicts kept in memory ( LRU, default : maxIpCache ?? 50000 )
    cleanCacheMax: 50000,
    // max number of concurrent live checks against the LAPI ( default : 100 )
    maxConcurrentChecks: 100,
    // how long ( s ) a failed check is remembered as backoff ( default : 10 )
    errorBackoffTtl: 10,
    // periodically scan the index and remove expired decisions, even if the
    // LAPI is down and the stream `deleted` events stop coming ( default : true )
    watchdog: true
    }
    }

    When a decision is found by the bouncer, req.decision will contain the decision

    These options are passed through the global CrowdSecHTTPMiddleware via the bouncer key of the constructor options. For example, to enable the live mode from the global middleware:

    const middleware = new CrowdSecHTTPMiddleware({
    url: process.env.CROWDSEC_URL,
    bouncer: {
    apiKey: process.env.CROWDSEC_API_KEY || '',
    subnetLevel: SubnetLevel.company,
    live: {
    enabled: true
    }
    }
    });

    On a local cache miss, the current request always passes and a live check (GET /v1/decisions?ip=<ip>) runs in the background. If the LAPI says the IP is banned, the decision is injected in the local index, so the next request from that IP is blocked. A malicious unknown IP can pass once, never twice.

    npm run bench compares the IP lookup strategies explored during the design (linear isInSubnet scan, current MapOfMaps index, packed MapSMI, sorted Uint32Array + binary search, custom open-addressing hash) across hit / miss lookups, subnetLevel presets and index setup.

    this library include debug, to debug, you can set the env variable :

    DEBUG=crowdsec-http-middleware:*
    
    APITypes
    EErrorsCodes
    LiveCheckErrorBehavior
    SubnetLevel
    __Error
    Alerts
    AxiosError
    BaseSubObject
    BouncerClient
    CrowdSecClient
    CrowdsecClientError
    CrowdSecHTTPMiddleware
    CrowdSecServerError
    Decision
    DecisionsBouncer
    DecisionsStream
    DecisionsWatcher
    TypedEventEmitter
    WatcherClient
    IBaseSubObjectOptions
    IBouncerAuthentication
    IBouncerClientOptions
    ICommonOptions
    ICrowdSecClientOptions
    ICrowdSecHTTPBouncerLiveOptions
    ICrowdSecHTTPMiddlewareOptions
    IHTTPOptions
    ITLSAuthentication
    IWatcherAuthentication
    IWatcherClientOptions
    CallBack
    CallBackParams
    commaSeparatedParams
    customPickFromAxiosError
    DecisionsStreamEvents
    getCurrentIpFn
    ICrowdSecHTTPBouncerMiddlewareOptions
    ICrowdSecHTTPWatcherMiddlewareOptions
    logFn
    logger
    loggerOption
    VERSION