Website Security: The Practices That Prevent Most Incidents
Most website compromises are not targeted. They are automated scanners finding a known vulnerability in outdated software, or a reused password on an admin account. Defending against the ordinary attacks covers the large majority of real risk.
This guide covers the practices that prevent most incidents, in rough order of effect, and what to do if a site is already compromised.
The measures that prevent most incidents#
In order of how much risk they remove per unit of effort.
- Keep software current. The overwhelming majority of compromises exploit a vulnerability with an available patch. This single item outweighs everything below it.
- Unique strong passwords plus two-factor authentication on every admin account, hosting panel, domain registrar and email account.
- Least privilege. Editors do not need administrator accounts. Remove accounts when people leave.
- HTTPS everywhere, with HSTS once you are confident every subresource is available over TLS.
- Tested backups, stored off the server. A backup on the compromised machine is encrypted along with everything else.
- Restrict the admin area by IP where practical, and always rate-limit login attempts.
- Remove what you do not use. Every inactive plugin, theme and old install is attack surface with no benefit.
Old, forgotten installs — a staging copy at /old, a test blog in a subfolder — are a common entry point precisely because nobody is updating them.
Input, output and the classic vulnerabilities#
These are developer responsibilities and they account for most of the vulnerabilities that are not "you did not update".
| Vulnerability | What it does | Prevention |
|---|---|---|
| SQL injection | Reads or destroys your database | Parameterised queries, always — never string concatenation |
| Cross-site scripting | Runs attacker script in a visitor’s session | Escape on output, contextually; a strict Content-Security-Policy |
| Cross-site request forgery | Performs actions as a logged-in user | Per-session tokens on every state-changing request |
| File upload abuse | Uploads and executes code | Validate type by content, store outside the web root, never execute |
| Broken access control | Users reach data that is not theirs | Check authorisation server-side on every request, not in the UI |
| Sensitive data exposure | Leaks keys and credentials | Environment variables, never in the repository |
| Server-side request forgery | Makes your server call internal systems | Allow-list outbound destinations |
Configuration and headers#
Cheap measures that close whole categories of problem, most of which take minutes to apply.
- Serve security headers: Content-Security-Policy, X-Content-Type-Options, Referrer-Policy, X-Frame-Options.
- Disable directory listing; make sure /.git, /.env and backup files are not reachable over HTTP.
- Turn off verbose error output in production — stack traces are reconnaissance.
- Block access to admin and configuration paths from the public internet where you can.
- Set cookies with HttpOnly, Secure and an appropriate SameSite value.
- Keep dependencies audited; a vulnerable library in your build is your vulnerability.
- Log authentication events and alert on unusual patterns.
If the site is already compromised#
Order matters here. Cleaning files before rotating credentials means the attacker simply returns through the same door.
- Take the site offline or into maintenance mode. Do not leave it serving malware to visitors.
- Preserve evidence: copy the logs and a snapshot of the files before changing anything.
- Rotate every credential — hosting, database, admin users, API keys, email. Assume all are known.
- Restore from a backup taken before the compromise, if you can identify one reliably.
- If you cannot, rebuild from source and re-import only data, never files of unknown origin.
- Patch the vulnerability that let them in. Without this step you will repeat the whole process.
- Scan for persistence: scheduled tasks, extra admin users, modified core files, injected content.
- Request a review in Search Console if the site was flagged, and check for injected spam pages.
- Notify affected users if personal data was exposed — in many jurisdictions within a legal deadline.
Restoring a backup without patching the entry point is the most common reason sites are compromised twice in a fortnight.
Frequently asked questions
Is a security plugin enough?
It helps with a few things — login rate limiting, file change monitoring, a basic firewall — and it is not a substitute for updates, strong credentials and least privilege. A site with a security plugin and eighteen months of missed updates is not secure. Fix the fundamentals first, then add tooling.
Do small websites really get attacked?
Constantly, and not because of who you are. Automated scanners test every reachable host for known vulnerabilities; small sites are attractive precisely because they are less likely to be patched. Compromised small sites are used for spam, phishing pages and redirects, which is why the traffic level of your site is irrelevant to the risk.
Where should backups be stored?
Somewhere the web server cannot write to, ideally with a different provider, with at least one copy that cannot be deleted by the same credentials that run the site. Ransomware and destructive attacks specifically target backups reachable from the compromised machine, and that is exactly the moment you need them.
What is the single highest-value security measure?
Applying updates promptly. It is unglamorous and it prevents more real compromises than everything else combined, because the attacks that actually happen are automated exploitation of known, patched vulnerabilities. Second is two-factor authentication on admin and hosting accounts.
website securitywebsite hackedsecurity best practicessql injectionxsswebsite backups