Five Security Basics Most Small Business Sites Skip
Form validation, session handling, and access control rarely make it onto a launch checklist — until something goes wrong. Here's what we check first.
Most small business sites are not compromised by anything sophisticated. They are compromised by automation — scripts that sweep thousands of domains looking for the same handful of oversights, and that do not care how small you are. Being a niche business is not cover, because nothing in the process ever looked at what your business does.
The good news is that the same short list closes most of it. Here is what we check on every build, in the order we check it.
1. Forms that trust what they are sent
A contact form is the one place you invite strangers to send you data, so it is the first thing worth hardening. Three things matter, and they are separate:
- Validate on the server, always. JavaScript validation is a convenience for honest users. It is not a control — anyone can post directly to your endpoint and skip it entirely.
- Bound every field. A description field with no length limit is an invitation to fill your disk or your database. Decide the maximum and enforce it.
- Escape on the way out, not just on the way in. Data that is safe in the database can still be dangerous when rendered into a page or an email.
One that catches people out: if submissions land in a CSV that staff open in Excel or Sheets, a field beginning =, +, - or @ is treated as a live formula. That is CSV injection, and the target is not your server — it is whoever opens the file. Neutralising those leading characters costs one line.
2. Session cookies with the flags left off
Sessions are where "it works" and "it is safe" diverge most quietly, because a misconfigured session behaves perfectly until someone attacks it. Four settings do most of the work:
HttpOnly— stops JavaScript reading the cookie, which limits what a cross-site scripting bug can steal.Secure— stops the cookie ever being sent over plain HTTP.SameSite— the main structural defence against cross-site request forgery.- Regenerate the session ID on login. Without this, an ID an attacker planted before login is still valid after it — session fixation, and it is invisible in testing.
A directive that is misspelled is not a weaker setting — it is no setting at all, applied silently. Configuration is worth verifying against what the server actually sends, not against what the code appears to say.
3. Access control that relies on nobody guessing the URL
If an admin page checks whether a link was shown rather than whether the visitor is allowed, then the URL is the password. The same applies to anything uploaded or generated: an invoice PDF at a predictable path is readable by anyone who can count.
Two rules cover most of it. Check permission on every request, in the handler, not in the template that draws the menu. And deny by default — a new page should be inaccessible until someone explicitly opens it, rather than public until someone remembers to close it.
4. Security headers, which cost nothing
These are a few lines of server configuration and they close entire categories of attack:
- Content-Security-Policy — the big one. Restricting scripts to your own origin makes most injected-script attacks fail even if something else lets them in.
- X-Content-Type-Options: nosniff — stops browsers second-guessing a file's type and executing something you served as data.
- Referrer-Policy — stops full URLs, which often carry identifiers, leaking to every third party you link to.
- Strict-Transport-Security — makes HTTPS sticky, so the first request cannot be downgraded.
A note on CSP: it is worth adopting before you need it, because retrofitting one onto a site full of inline scripts is genuinely painful. Building without inline scripts from the start makes the strictest policy the easy one.
5. Knowing whether anything happened at all
The last item is not prevention. Most small sites cannot answer basic questions after an incident — when did this change, who was logged in, was this the first attempt or the thousandth — because nothing was ever recorded.
You do not need a monitoring platform. Timestamped records of logins, admin changes, and failed attempts, kept somewhere that survives the thing you are investigating, answer most of it. Two cautions: keep them out of the web root, and do not log the sensitive values themselves. A log full of passwords is a breach waiting for a reader.
The pattern underneath
None of this is advanced, and that is the point. These are not the measures that stop a determined, targeted attacker — they are the ones that make your site uninteresting to the automated sweep that was never targeting you in the first place. That covers the overwhelming majority of what actually goes wrong.
Every site we build gets this pass whether or not security was the reason we were called, because a site that is fast, well-written and quietly compromised is not a site that worked. If you want it looked at properly, that is what our web security work is.