LAtS - a simple anti-DDoS/anti-abuse solution for Glitch

After reading countless threads of people having their sites attacked, and starting to get really bored, I came up with Lightweight Access to Service - a simple solution to Denial of Service attacks (get the name now?).

How it works

LAtS works by creating a browser cookie with a random ID/token and saving it to an array. If the same IP address doesn’t send that random ID/token on an another request (this would happen when using a new browser, or a bot is attacking your website), a new token is generated and stored in that array (along with the previous tokens). When the amount of generated tokens hits 8, the user is blocked until the next time your app restarts.

Why it works (and a simpler explaination)

Bots often don’t keep cookies when they run their code a second time. After 8 attempts to attack your website, they will be blocked from accessing it.

Installation

Simply install cookie-parser and add this code to your Express app somewhere at the top (e.g. after const app = express()):

// Lightweight Access to Service (LAtS) - a simple anti-DDoS solution.
const crypto = require("crypto");
const cookieParser = require("cookie-parser");
var ips = [];

app.use(cookieParser());
app.use((req, res, next) => {
  // Clear the IP "database" after 15,000 IPs have been logged in order to prevent memory leaks
  if (ips.length > 15000) ips = [];
  
  var addUser = (ip, token) => ips.push({ ip: ip, tokens: [token] }); // we're going to change this so it's better to put it as a function
  var token = crypto.randomBytes(8).toString("hex"); // this token will give the user access to the service
  var ip = req.headers["x-forwarded-for"].split(",")[0];
  var user = ips.find(users => users.ip == ip);
  if (user) {
    var addUser = (ip, token) => user.tokens.push(token);
    // block the user if they reach 8 generated tokens (a simple bot won't remember cookies, thus we can ban it after 8 attempts)
    if (user.tokens.length > 9) {
      console.log(`LAtS has just blocked a user with an IP address of ${ip}.`)
      return res.status(429).send("You seem like a bot and have been blocked. Please try again later.");
    }
  }
  // ------------------------------------------------------------------------------------------------------
  // the part below is responsible for actually generating the cookies and letting the user in.
  // it makes a new cookie if (a) the user doesn't have one yet, or (b) has a invalid cookie (a token that
  // doesn't exist in the "database", which could be caused by restarting your Glitch project).
  // ------------------------------------------------------------------------------------------------------
  if (user) 
    var ifTokenExists = user.tokens.includes(req.cookies['_verified']);
  else
    var ifTokenExists = false;
  if (typeof req.cookies["_verified"] === "undefined" || !ifTokenExists) {
    res.cookie("_verified", token); // add the verified cookie to the user
    addUser(ip, token); // add their IP address and a non-secret "access token" to our array
  }
  next(); // let the user in, i guess, they have the cookie now
});

Will this cause my site’s visitors to complete a captcha, or something?

No. LAtS does all of its work silently, without bothering your users or slowing down your site.

Warnings and notes

  • LAtS is not a silver bullet. Some smarter bots save cookies, however the more common ones don’t.
  • This script was made in ~30 minutes and might look like a mess to some. I’m open for any improvements.
  • To further improve the security of your site, use express-rate-limit to keep attackers from spamming your site with requests (make sure to use app.set('trust proxy', 1); with that) and maybe block some user agents (like curl).
3 Likes

Woah! This looks very interesting!

1 Like

This would work much better with a server storage. You can use something like SQLite and Socket.io to make it so that each time you visit a page it is logged. It will increase every request and if it goes over a certain number in a time frame, it will block the request. And after a while (let’s say 10 minutes) it will clear the log of that user.

This is quite neat, however, it won’t prevent against DDoS attacks, here is why:

Even if requests get blocked, they still make it to the project. You would need to implement this on the proxy level to get true results. But still, very neat!

3 Likes

Yes, but the attacker will only receive a very small amount of data (which shouldn’t significantly slow down your site) and since the requests are blocked, they won’t be able to mess with your app (if it, for example, uses a database).

3 Likes

Suggestion in that case: Add status codes when you get blocked.
I also want to compliment on your coding style, everything is well commented.

I think you would hate me since I barely comment my code. And spaghetti. The code OP has is super nice and readable.

express-rate-limit does exactly that. LAtS is a solution that does not use ratelimits to prevent attacks in order to ensure compatibility. Also, bots might just sleep for a bit between requests, bypassing ratelimits.

Like I said in the “Warnings and notes” section, you should utilize both express-rate-limit and LAtS.