SSL/TLS (1-6)
- **TLS certificate is valid and not expired.** Check expiration date. Set up automated renewal with [Let's Encrypt](https://letsencrypt.org/) or your CA.
- **TLS 1.2 or higher.** TLS 1.0 and 1.1 are deprecated. Disable them in your server config. Use the [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/).
- **HSTS header is set.** `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`
- **HTTP redirects to HTTPS.** All HTTP requests should 301 redirect to HTTPS. Not 302.
- **No mixed content.** Every resource (scripts, stylesheets, images, fonts) loaded over HTTPS.
- **Certificate chain is complete.** Intermediate certificates are included. Test with `openssl s_client -connect yoursite.com:443`.
## Security Headers (7-14)
- **Content-Security-Policy is set.** At minimum: `default-src 'self'`. Add exceptions as needed. See [MDN CSP guide](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP).
- **X-Frame-Options is DENY or SAMEORIGIN.** Prevents clickjacking.
- **X-Content-Type-Options is nosniff.** Prevents MIME sniffing attacks.
- **Referrer-Policy is set.** `strict-origin-when-cross-origin` is a good default.
- **Permissions-Policy disables unused features.** `camera=(), microphone=(), geolocation=()`
- **Server header doesn't leak version info.** Remove or obscure the `Server` and `X-Powered-By` headers.
- **Cross-Origin-Opener-Policy is same-origin.** Isolates browsing context.
- **Cache-Control is set for sensitive pages.** `no-store` for authenticated pages to prevent browser caching of sensitive data.
## Authentication (15-22)
- **Passwords are hashed with bcrypt, scrypt, or Argon2.** Never MD5, SHA-1, or SHA-256 without salt.
- **Password minimum length is 8+ characters.** Check against the [HaveIBeenPwned](https://haveibeenpwned.com/API/v3) breached password list.
- **Login endpoint is rate-limited.** Maximum 10 attempts per IP per minute. Return 429 after limit.
- **CSRF tokens on all state-changing forms.** Login, registration, password change, account settings.
- **Session tokens are regenerated after login.** Prevents session fixation attacks.
- **Cookies have Secure, HttpOnly, and SameSite flags.** `Set-Cookie: session=...; Secure; HttpOnly; SameSite=Lax`
- **MFA is available for admin accounts.** TOTP (authenticator app) at minimum.
- **Password reset tokens expire.** 1 hour maximum. Single-use. Invalidated after password change.
## Input Validation (23-28)
- **All user input is validated server-side.** Client-side validation is for UX only. An attacker bypasses JavaScript in seconds.
- **Input length limits are enforced.** Names: 100 chars. Emails: 254 chars. URLs: 2048 chars. Prevent memory and storage abuse.
- **File uploads are validated.** Check MIME type, file extension, and file size. Store outside the webroot. Generate random filenames.
- **HTML output is encoded.** Use your framework's built-in escaping (React JSX, Django templates, Jinja2 autoescaping). Never use `innerHTML` with user data.
- **URLs in redirects are validated.** Open redirect vulnerabilities let attackers redirect users to phishing sites using your domain.
- **JSON and XML parsers reject external entities.** Disable XXE processing. Most modern parsers do this by default.
## Database (29-34)
- **All queries use parameterized statements.** No string concatenation in SQL. Ever. Use your ORM or prepared statements. See [bobby-tables.com](https://bobby-tables.com/).
- **Database user has minimum privileges.** The application's database account should not have DROP, CREATE, or GRANT permissions.
- **Database is not exposed to the internet.** Bind to localhost or a private network. No public port 3306/5432/27017.
- **Default database credentials are changed.** No `root` with no password. No `postgres/postgres`.
- **Sensitive data is encrypted at rest.** Use database-level encryption (TDE) or application-level encryption for PII fields.
- **Database backups are encrypted and tested.** An unencrypted backup is a data breach waiting to happen. Test restore procedures monthly.
## API Security (35-40)
- **CORS is configured with specific origins.** Never `Access-Control-Allow-Origin: *` with credentials. Specify allowed domains.
- **API authentication on every endpoint.** No endpoints that assume "nobody will find this URL."
- **Rate limiting on all public endpoints.** Prevent abuse, scraping, and brute force attacks.
- **Response bodies don't leak internal data.** No stack traces, database column names, or file paths in error responses.
- **API versioning is in place.** Breaking changes don't affect existing clients without notice.
- **Request size limits are enforced.** Prevent request body abuse. Typically 1-10 MB depending on use case.
## Deployment (41-46)
- **Debug mode is off in production.** No `DEBUG=True` (Django), no `app.debug = True` (Flask), no verbose error pages.
- **Sensitive files are not accessible.** `.env`, `.git/`, `docker-compose.yml`, `package.json` should return 404.
- **Admin panels are protected.** Not accessible on the public URL. Use IP allowlisting, VPN, or a separate domain.
- **Dependencies are updated and audited.** Run `npm audit`, `pip audit`, or your package manager's security check.
- **Secrets are in environment variables.** Not in source code, not in config files committed to git. Use a secret manager.
- **Docker images use non-root users.** `USER node` or `USER appuser` in your Dockerfile. Never run as root.
## Monitoring (47-50)
- **Security events are logged.** Login attempts, access denied, input validation failures, errors. Include timestamp, user, IP, action.
- **Logs are stored securely.** Centralized logging (ELK, CloudWatch, Datadog). An attacker who compromises the app should not be able to delete logs.
- **Alerts are configured for anomalies.** Spike in 403/401 errors, login failures from single IP, unusual data export patterns.
- **Regular security scans.** Automated vulnerability scanning after every deployment. [ismycodesafe.com](/) covers 110 checks across SSL, headers, ports, OWASP paths, CVEs, SEO, and AI content detection — free.
This article was originally published on ismycodesafe.com.
Want to check your website's security? Run a free scan
Top comments (0)