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