Guide
Web security best practices
A practical, no-hype checklist of web application security best practices - the controls that actually stop real attacks, grouped by area so you can work through them and know what to verify.
Jump to the checklist ↓Security is a set of habits, not a single feature
Most web application breaches do not come from exotic zero-days. They come from familiar gaps: a missing authorization check, an unparameterized query, a hardcoded secret, an out-of-date dependency, a session cookie without the right flags. The good news is that the same short list of fundamentals prevents the overwhelming majority of real-world attacks - and none of it is a secret.
The checklist below groups those fundamentals into the areas that matter: authentication and sessions, input validation, access control, configuration and headers, dependencies and secrets, TLS, and logging. Each item is a concrete practice you can check your application against. Treat security as defense in depth - no single control is enough, but layered together they raise the cost of an attack sharply. The final section covers how to verify these are genuinely in place rather than assumed.
The web security best practices checklist
Work through each group and confirm every item holds for your application. The controls are ordered roughly by how often their absence leads to a breach.
Authentication & session management
- Store passwords with a slow, salted hash designed for the job (bcrypt, scrypt, or Argon2) - never plain text, MD5, or SHA-1.
- Enforce a length-first password policy (a minimum of 8-12 characters) and check new passwords against known-breached lists instead of forcing arbitrary complexity rules.
- Offer multi-factor authentication and require it for administrative and high-privilege accounts.
- Generate session identifiers with a cryptographically secure random source, rotate them on login and privilege change, and invalidate them on logout.
- Set session cookies with the Secure, HttpOnly, and SameSite attributes, and give sessions a sensible idle and absolute timeout.
- Apply rate limiting and account lockout or exponential backoff to login, password-reset, and MFA endpoints to blunt credential stuffing and brute force.
- Return generic messages on failed login and password reset so you do not reveal whether an account exists.
Input validation & injection prevention
- Validate input on the server against an allowlist of expected type, length, format, and range - client-side checks are for usability, not security.
- Use parameterized queries or an ORM for every database call so user input can never be parsed as SQL.
- Prevent cross-site scripting with context-aware output encoding, and prefer frameworks that escape by default over manual string building.
- Add a Content-Security-Policy as defense in depth against XSS, and avoid inline scripts and eval so the policy can stay strict.
- Guard against command injection by avoiding shell calls with user input; when unavoidable, use argument arrays and strict validation, never string concatenation.
- Defend against SSRF by validating and allowlisting outbound URLs and blocking requests to internal address ranges and cloud metadata endpoints.
- Set upload restrictions on file type, size, and storage location, and serve user files from a separate domain without executable permissions.
Access control & authorization
- Enforce authorization checks on the server for every request, on every object - never trust a hidden field, client role, or the mere absence of a link.
- Deny by default: a resource is inaccessible unless a rule explicitly grants the current user access.
- Stop insecure direct object references (IDOR) by verifying the authenticated user actually owns or may access the record identified in the request.
- Apply the principle of least privilege to users, service accounts, and API tokens - grant only the permissions each role genuinely needs.
- Protect state-changing requests from cross-site request forgery with anti-CSRF tokens or the SameSite cookie attribute.
- Keep authorization logic centralized and consistent rather than re-implemented per endpoint, where gaps are easy to miss.
Secure configuration & security headers
- Disable directory listings, verbose stack traces, and debug endpoints in production, and change every default credential.
- Send HTTP Strict-Transport-Security (HSTS) so browsers only ever connect over HTTPS.
- Set X-Content-Type-Options: nosniff to stop MIME-type sniffing, and use a restrictive frame policy to prevent clickjacking.
- Configure CORS narrowly - name the specific origins you trust rather than reflecting arbitrary origins or using a wildcard with credentials.
- Remove response headers that leak framework and version details, and strip server banners where you can.
- Harden the platform: keep the OS, web server, and runtime patched, and expose only the ports and services the application actually needs.
Dependency & secrets hygiene
- Keep an inventory of third-party dependencies and scan them continuously for known vulnerabilities (software composition analysis).
- Patch or replace vulnerable libraries promptly, and remove packages you no longer use.
- Keep secrets - API keys, database passwords, tokens - out of source control and configuration files; use environment variables or a dedicated secrets manager.
- Rotate credentials on a schedule and immediately after any suspected exposure or staff change.
- Scan commits and history for accidentally committed secrets, and treat any leaked secret as compromised even after removal.
- Pin and verify dependency integrity (lockfiles, checksums) to reduce supply-chain and typosquatting risk.
TLS & data protection
- Serve all traffic over HTTPS and redirect HTTP to HTTPS - there is no such thing as a page that does not need it.
- Support only modern TLS versions (1.2 and 1.3) and strong cipher suites; disable SSLv3, TLS 1.0, and TLS 1.1.
- Keep certificates valid and automate renewal so an expired certificate never becomes an outage or a scary browser warning.
- Encrypt sensitive data at rest, and minimize what you collect and retain in the first place.
- Never log passwords, full card numbers, session tokens, or other secrets, and mask sensitive fields in application logs.
Logging, monitoring & response
- Log security-relevant events - authentication, access-control failures, input-validation failures, and server errors - with enough context to investigate.
- Centralize logs and alert on anomalies such as spikes in failed logins, authorization denials, or unusual data access.
- Protect log integrity so an attacker cannot quietly erase their tracks, and retain logs long enough to support an investigation.
- Have a written incident-response plan and rehearse it, so the first time you handle a breach is not during a real one.
- Test your defenses regularly - a control you never verify is a control you only hope works.
How to verify these are actually implemented
A checklist tells you what should be true. It does not tell you what is true. The only way to know that your authorization checks hold, that your inputs are really being sanitized, and that no forgotten debug endpoint is exposed is to test the running application the way an attacker would.
That is what a penetration test does. TurboPentest runs a full agentic pentest across your network, web app, API, and external attack surface - probing exactly the controls above and reporting which ones fail, with a proof of concept and a fix for each. Connect a GitHub repository read-only and it also reads your source code (white-box), so it catches the injection, secret, and misconfiguration issues on this list at their root, mapped to CWE, OWASP, and ASVS. It runs autonomously and delivers a report in a few hours, for $99 per target. If it finds nothing actionable, your next pentest is free.
Web security best practices FAQ
What are the most important web security best practices?+
The highest-impact practices are: enforce authorization on the server for every request, use parameterized queries and output encoding to stop injection and XSS, hash passwords with bcrypt/scrypt/Argon2 and offer MFA, serve everything over modern TLS, keep dependencies patched, keep secrets out of source control, and log and monitor security-relevant events. Most real-world breaches trace back to a gap in one of these fundamentals rather than an exotic attack.
How do I secure a web application?+
Work through the fundamentals in layers: authenticate and manage sessions correctly, validate all input on the server and encode output, enforce least-privilege access control on every object, harden your configuration and set security headers, keep dependencies and secrets clean, require HTTPS with strong TLS, and log and monitor for abuse. Then verify the result - a penetration test confirms that the controls you believe are in place actually hold up against a real attacker.
What is the difference between authentication and authorization?+
Authentication proves who a user is (login, MFA, session management). Authorization decides what that authenticated user is allowed to do (which records they can read, which actions they can perform). Both must be enforced on the server. Broken access control - failing to check authorization on every object - is one of the most common and damaging web application flaws.
Are security headers enough to secure a website?+
No. Security headers like HSTS, Content-Security-Policy, and X-Content-Type-Options are valuable defense in depth, but they mitigate rather than fix underlying flaws. A strong CSP reduces the impact of XSS but does not replace output encoding; HSTS enforces HTTPS but does not fix a broken authorization check. Treat headers as one layer among authentication, input validation, access control, and the rest.
How often should I test my web application's security?+
Run a penetration test at least annually and after any significant change - a new feature, an authentication change, a major dependency upgrade, or a move to new infrastructure. Continuous dependency scanning and static analysis should run on every build. The goal is to catch regressions early rather than discover them after they ship. TurboPentest lets you re-test on demand for $99 per target.
Know where you actually stand
Follow the checklist, then prove it. TurboPentest tests your live app against these best practices and shows you exactly what holds and what does not - a full report in a few hours, $99 per target. See pricing
Written and reviewed by
Michel Chamberland - Founder & CEO, IntegSec
CISSP, OSCP, OSCE, CEH, GIAC, CCSK · 20+ years in offensive security
Michel has spent 20+ years on offensive security teams including IBM X-Force Red and Trustwave SpiderLabs, leading penetration tests, red team engagements, and breach response for Fortune 500 customers. He is the founder of IntegSec and the architect of TurboPentest.