I've been learning and experimenting with NodeJS, and the project I'm using is to port a homemade content management system (CMS) written using the Linux/Apache/MySQL/PHP combination. One of the areas I am trying to update is protecting against spam on a contact form. The NodeJS version is based upon Linux/Mongo/Nginx/Javascript (why Mongo? because I wanted to learn how to work with it!)

I have a server side check that helps to reduce spam by assigning a unique ID to each form downloaded and having that ID entered into the database along with a pointer to the form handler. Each form ID can only be used once, and if a form requires such an ID and no ID is present - then no form handler is called for. (This also helps to secure access to the system through other forms such as administrative functions.)

I understand there are more checks I could use server side and would love to hear about those, but I also want to focus right now on the client side. Do folks have any suggestions for captcha-less forms that are resistant to spamming?

Dani AI

Generated

Good start — the one-time form-ID approach is a solid foundation. Tighten it by signing the token server-side (HMAC) and giving it a short expiry; that prevents guessing and lets you reject reused or stale tokens. Also keep a small “used” flag in Mongo so a token can only be consumed once. Signed nonces and layered controls are standard anti-automation guidance. (owasp.org)

Example token sign/verify (Node built-in crypto):

const crypto = require('crypto');

function signForm(id, ttlMs = 5*60*1000) {
  const expires = Date.now() + ttlMs;
  const payload = `${id}:${expires}`;
  const mac = crypto.createHmac('sha256', process.env.FORM_SECRET).update(payload).digest('hex');
  return `${payload}:${mac}`;
}

function verifyForm(token) {
  const [id, expires, mac] = token.split(':');
  const expected = crypto.createHmac('sha256', process.env.FORM_SECRET).update(`${id}:${expires}`).digest('hex');
  return mac === expected && Date.now() <= Number(expires);
}

Add low-friction, captcha-less layers: a hidden honeypot field, a small time-check (reject submissions faster than humanly possible), and an optional JS-only field injected at submit time to catch bots that don’t run scripts. Keep names random and rotate them if you can; also ensure the honeypot is invisible to sighted users but not inadvertently hidden from screen-readers. (help.formspree.io)

Server-side, rate-limit the endpoint (express-rate-limit or similar), then run checks in order: rate-limit, verify signature, check honeypot empty, verify minimum form-fill time, then accept and mark token used. Example Express snippet:

import rateLimit from 'express-rate-limit';

const contactLimiter = rateLimit({ windowMs:3600000, max:5 });
app.post('/contact', contactLimiter, (req,res)=>{
  if (req.body.website) return res.status(200).end(); // honeypot
  if (!verifyForm(req.body.formToken)) return res.status(400).send('Invalid token');
  if (Date.now() - Number(req.body.formStart) < 3000) return res.status(400).send('Too fast');
  // proceed (mark token used, save to Mongo, send email)
});

Rate-limit middleware and external stores are recommended for scale. (npmjs.com)

As and noted, IP/country blocks help but can block legitimate users and are evasion-prone; treat them as one layer and monitor logs before applying broad blocks. For high-volume sites consider a WAF or managed bot service; always test for caching, accessibility, and false positives when adding invisible checks. (f5.com)

Recommended Answers

All 2 Replies

There are many ideas to combat form spam.

If it's just a contact from you to them email entry, then they get emails from you and your email management handles duplicates and failed attempts.

I think you're using the right words by asking for spam resistant as there is nothing spam proof. Something will get through and for that you have to think about adding code/rules for those.

For example my country has strict rules about dealing with some countries so a simple rule would be to exclude by IP or email domain those countries.

Agree with this, excluding certain countries works quite well to eliminate a large percentage of spam.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.