Skip to main content

Rate Limit Bypass Detection

Traditional rate limiting by IP fails against bots that use proxy pools, rotating residential proxies, or cloud infrastructure. ShieldLabs provides a stable DeviceID and VisitorID that survive IP changes.

The problem

Bot strategy:
  Request 1 → IP: 1.2.3.4   → blocked by rate limiter
  Request 2 → IP: 5.6.7.8   → new IP, not blocked
  Request 3 → IP: 9.10.11.12 → new IP, not blocked
  ...
The browser fingerprint (DeviceID) remains the same across all requests even when the IP changes.

Rate limiting by DeviceID

const redis = require('redis');
const client = redis.createClient();

app.post('/shieldlabs/webhook', async (req, res) => {
  const { Data } = req.body;
  res.status(200).end();

  const key = `rate:device:${Data.DeviceID}`;
  const count = await client.incr(key);
  if (count === 1) {
    await client.expire(key, 60); // 60-second window
  }

  if (count > 20) {
    // More than 20 requests/minute from same device
    await blockDevice(Data.DeviceID);
    await logRateLimitBypass(Data);
  }
});

ShieldLabs built-in rate limiting

ShieldLabs automatically detects and bans devices exceeding 10 checks per minute. When triggered, all subsequent webhooks for that device return:
{
  "Score": 999,
  "Details": [
    { "Value": 999, "Description": "User has been banned 1H, to many requests" }
  ]
}
You can use Score === 999 as a fast path to block without processing other signals.

Detecting IP-cycling bots

Even if the bot uses a fresh IP each time, the Trust Score reveals the pattern:
app.post('/shieldlabs/webhook', async (req, res) => {
  const { Data } = req.body;
  res.status(200).end();

  // Track unique IPs per DeviceID
  await redis.sadd(`ips:device:${Data.DeviceID}`, Data.IP);
  await redis.expire(`ips:device:${Data.DeviceID}`, 3600);
  const uniqueIPs = await redis.scard(`ips:device:${Data.DeviceID}`);

  if (uniqueIPs > 5) {
    // Same device, 5+ different IPs in 1 hour
    await flagDevice(Data.DeviceID, 'ip_cycling');
  }

  // Also check signals
  if (Data.Score >= 100) {
    await blockDevice(Data.DeviceID);
  }
});

Blocking at the application level

Once a DeviceID is flagged, block it in your login/checkout middleware:
async function checkDeviceBlock(req, res, next) {
  const deviceId = req.headers['x-shield-device-id']; // if you pass it
  // Or look it up from your session → requestId → webhook data

  if (deviceId && await isDeviceBlocked(deviceId)) {
    return res.status(429).json({ error: 'Too many requests' });
  }
  next();
}