Server-side safety

Limit abuse and automated submissions

Add rate limits, honeypots, challenge widgets, and monitoring without making the form unnecessarily hostile to real people.

8 minute lesson

~~~

Public forms attract spam, repeated submissions, and automated abuse. No single control separates every person from every bot.

Start by defining what abuse costs. A contact form may send email. A password-reset form may send messages and reveal account behavior. A file form consumes storage and processing time. Protect the expensive operation, not only the HTML page.

Apply server-side rate limits using signals that fit the endpoint. An IP address is useful but imperfect because many people can share one address and attackers can rotate addresses. For authenticated actions, an account or user ID is often a stronger key. Sensitive flows may need both.

When a limit is exceeded, return 429 Too Many Requests and a generic message. Keep enough server-side logging to see patterns without storing submitted secrets.

A honeypot can catch simple automation:

<div hidden>
  <label for="company-website">Leave this field empty</label>
  <input id="company-website" name="companyWebsite" tabindex="-1" autocomplete="off">
</div>

The server quietly rejects or discards submissions that fill it. Do not rely on a honeypot alone; capable bots can detect it.

Add a challenge such as Turnstile only when simpler controls are not enough. A challenge adds friction and can fail for real people, so use it where the abuse cost justifies it.

Other useful layers include request-size limits, duplicate detection, minimum completion time used as a signal, account verification, and queues for expensive work.

Do not block solely because a request is fast or uses an unfamiliar browser. Signals can be wrong. Combine them and monitor the result.

Test a burst of submissions, repeated identical content, a filled honeypot, and a valid slow submission. Confirm the endpoint limits abuse without losing ordinary messages.

Lesson completed