37 Audits
JourneysHow to secure your website

How to secure your website

Patch what you run, close what is exposed, and harden HTTPS, cookies and browser headers, one checked step at a time.

Most websites are not broken into through clever attacks. They are broken into through an old version with a published exploit, an admin page that answers anyone, a cookie a script can read, or a header nobody set. Each of these is quick to fix once you know it is there. The hard part is that they are spread across your code, your web server, your CDN and your hosting settings.

This journey puts them in order. You start with what you run and whether it is patched, close the pages that should not be public, and then work outward through HTTPS, cookies and the headers that switch on browser protections. The last two steps cover what cannot be seen from outside: how people sign in, and what sits behind the site.

Most steps have an auditor that checks the result on your monitored URL. A few complete by hand, either because nothing outside your network can verify them or because a correct setup can still leave a finding you have to judge yourself. Each of those steps says so.

Running Liferay? How to secure your Liferay site covers the same ground with Liferay settings and checks your version against Liferay's advisories. Related journeys: How to secure your email and How to keep your website online.

Steps

Open a step to read it
  1. 1
    Know what you run

    You cannot patch what you have not written down. A typical site runs a framework or CMS, plugins or packages, a language runtime, a web server and often a CDN, and each of them publishes security fixes on its own schedule.

    Do this

    • List the software behind the site with the version in production: CMS or framework, plugins and themes, runtime (Node, PHP, Java, Python), web server, database

    • Open the project that owns this URL, find Software Stack and add the main platform with its version. 37 Audits uses it to pick platform-specific checks

    • Note where each one publishes security advisories (GitHub security advisories, a mailing list, a release page) and subscribe

    Done when the list exists and the project's Software Stack names the platform and version that run in production. Update both after every upgrade.

  2. 2
    Patch known vulnerabilities

    Every published vulnerability comes with the versions it affects, and attackers read the same lists you do. A known vulnerability in a version you run is the easiest way into the site, and automated scanners try them within days of publication.

    Do this

    • Turn on automated dependency alerts: Dependabot or Renovate on GitHub, npm audit, composer audit, pip-audit, or your CMS's update screen

    • For each alert on something that runs in production, read which version fixes it and update. If you cannot update now, apply the workaround the advisory describes

    • Remove plugins, themes and packages you do not use. They still count

    • Look up your platform and server versions on endoflife.date and plan an upgrade for anything out of support: it gets no fixes at all

    Done when nothing in production has an open advisory you have not either fixed or consciously accepted. On Liferay, the CVE Auditor checks this automatically against Liferay's advisories; for other platforms this step completes by hand.

  3. 3
    Close the admin and debug pages
    Verifies with Protected URL Auditor

    Admin consoles, setup wizards, debug pages, API explorers and forgotten backup folders are meant for you, not for the internet. When they answer anonymous visitors they give an attacker a sign-in form to brute force, or worse, a page that needs no sign-in at all.

    The Protected URL Auditor requests common paths without signing in: /admin, /administrator, /dashboard, /manage, /config, /setup, /install, /debug, /dev, /test, /backup, /logs, /internal, /api and others. A path is protected when it answers 401, 403 or 404, or redirects to a sign-in page.

    Do this

    • Run the auditor and look at every path it reports as open

    • Remove what should not exist in production: installers, test pages, debug toolbars, old backups

    • Put admin areas behind sign-in, and if only your team uses them, also restrict them by IP address or VPN at the web server or CDN

    • Turn off debug mode and verbose error pages in production

    • Add paths of your own, such as /wp-admin or a custom console, in the auditor's paths preference on the URL's Configuration tab

    Done when the auditor reports every path as protected.

  4. 4
    Stop advertising server versions
    Verifies with Server Fingerprint Auditor

    Knowing the exact version of your web server or framework lets an attacker pick the right exploit without probing. These versions travel in response headers that no visitor needs.

    The Server Fingerprint Auditor reads Server, X-Powered-By and X-AspNet-Version. It fails when one of them carries a version number, and warns when they are present without one.

    Do this

    • Nginx: server_tokens off. Apache: ServerTokens Prod and ServerSignature Off

    • Express: app.disable('x-powered-by'). PHP: expose_php = Off. ASP.NET: remove X-AspNet-Version and X-Powered-By in web.config

    • Check error pages too: a default 404 or 500 page often prints the version

    Done when no header carries a version number. Many hosts and CDNs (Cloudflare, Vercel, Netlify) always send a bare Server header you cannot remove, which leaves a warning, so this step completes by hand.

  5. 5
    Redirect HTTP to HTTPS
    Verifies with HTTP Redirect Auditor

    Anyone who types your address without https:// starts on plain HTTP. Until the redirect happens, the request can be read or changed on the way, including a session cookie that is not marked secure.

    The HTTP Redirect Auditor requests the http:// version of your URL. It fails when there is no redirect or when it goes somewhere that is not HTTPS, and warns on a temporary 302.

    Do this

    • At the web server, load balancer or CDN, answer every request on port 80 with a 301 to the same path on HTTPS. On Cloudflare this is Always Use HTTPS; most hosting platforms do it by default

    • If TLS ends at a proxy, make sure the application knows the original request was HTTPS (X-Forwarded-Proto), or it will build http:// links and redirect loops

    Done when the auditor reports a permanent redirect to HTTPS.

  6. 6
    Serve a valid certificate on modern TLS
    Verifies with Certificate AuditorVerifies with TLS Version Auditor

    The Certificate Auditor validates the chain the way a browser does: expired, revoked, self-signed, wrong hostname, untrusted root or missing intermediate all fail. The TLS Version Auditor tries each protocol version and fails when TLS 1.0 or 1.1 is still accepted.

    Do this

    • Install the full chain, intermediates included. A missing intermediate works in some browsers and fails in API clients and mobile apps

    • Check that the certificate names every hostname the site answers on, www included

    • Automate renewal with ACME (Let's Encrypt, ZeroSSL) or your host's managed certificates

    • Turn off TLS 1.0 and 1.1 and turn on TLS 1.3. With 1.2 alone the auditor warns and this step will not complete by itself. On a CDN this is a setting (Cloudflare: Minimum TLS Version and TLS 1.3)

    Done when both auditors pass.

  7. 7
    Turn on HSTS
    Verifies with HSTS Preload Auditor

    The redirect from step 5 protects a visitor only after the first plain request. HSTS tells the browser to skip that request and use HTTPS from the start, for as long as you say.

    The HSTS Preload Auditor expects the header in the form browsers accept for their preload list: a max-age of at least one year, includeSubDomains and preload.

    Do this

    • First confirm that every subdomain of your domain serves HTTPS. includeSubDomains applies to all of them, including old staging servers and internal tools

    • On HTTPS responses, send Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

    • If you are unsure, start with a short max-age and without preload, and raise it once nothing breaks

    • Optionally submit the domain at hstspreload.org so browsers ship with it

    Done when the auditor passes. Browsers remember this header for the whole max-age, so removing it later does not undo it quickly.

  8. 8
    Remove mixed content
    Verifies with Mixed Content Auditor

    A page served over HTTPS that loads an image or script over http:// is only partly protected. Browsers block the scripts and warn about the rest.

    The usual sources are content, not code: images pasted into posts with http:// links, hardcoded URLs in templates, old embeds and third-party widgets.

    The Mixed Content Auditor loads the page in a browser and fails for every request or element that uses http://.

    Do this

    • Run the auditor and open the findings to see each URL

    • Fix the URL where it lives: the post, the template, the theme, the widget configuration

    • Use relative or https:// URLs in new content. A database search and replace of http://your-domain fixes most CMS content in one go

    Done when the auditor finds no http:// resource. Run it on your busiest pages too, not only the home page.

  9. 9
    Secure your cookies
    Verifies with Cookie Auditor

    A session cookie is the signed-in user. If a script can read it, or it travels over plain HTTP, the session can be stolen.

    The Cookie Auditor checks every cookie set by the monitored URL. A cookie without HttpOnly fails, and so does SameSite=None without Secure. A missing Secure or SameSite is a warning.

    Do this

    • Set session and authentication cookies with Secure; HttpOnly; SameSite=Lax (or Strict if nothing cross-site needs them). Most frameworks have one setting for this

    • Give cookies the shortest lifetime that works, and a narrow Path and Domain

    • Review the other cookies in the findings. A cookie a front-end script must read cannot be HttpOnly; make sure it holds nothing sensitive

    Done when the auditor passes, or every remaining finding is a cookie you looked at and decided to accept, in which case mark the step complete by hand.

  10. 10
    Send the browser security headers
    Verifies with X-Frame-Options AuditorVerifies with X-Content-Type-Options AuditorVerifies with Referrer Policy AuditorVerifies with Permissions Policy Auditor

    Four response headers switch on protections that browsers leave off by default. They are attached together here because you set them in the same place: the web server, the CDN, or your framework's headers config (next.config.js, vercel.json, _headers on Netlify and Cloudflare Pages).

    Do this

    • X-Frame-Options: SAMEORIGIN stops other sites from framing yours (clickjacking). If you embed your own pages in an iframe elsewhere, allow that origin in CSP frame-ancestors instead

    • X-Content-Type-Options: nosniff stops browsers from guessing file types, which matters for anything users upload

    • Referrer-Policy: strict-origin-when-cross-origin keeps full page URLs, with tokens or search terms in them, from leaking to other sites

    • Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=() turns off device features the site does not use. Allow only the ones a page needs

    • Set them on every response, error pages and static files included

    Done when all four auditors pass.

  11. 11
    Add a Content Security Policy
    Verifies with Content Security Policy Auditor

    A Content Security Policy tells the browser which sources of script, style, images and frames the page may use. It is the strongest defence against injected script, and the hardest header to get right, because every analytics tag, chat widget and font host has to be listed.

    The CSP Auditor fails when the header is missing, and warns when the policy is report-only or allows unsafe-inline or unsafe-eval.

    Do this

    • Start with Content-Security-Policy-Report-Only and a report-to endpoint, and watch what real pages would break

    • List the origins you depend on: CDN, analytics, tag manager, payments, maps, video

    • Replace inline scripts with files, or use nonces or hashes. Most modern frameworks can add a nonce per request

    • Include frame-ancestors 'self', object-src 'none' and base-uri 'self'

    • Switch to the enforcing header once the reports are quiet

    Done when the enforcing header is live and the pages you care about still work. Many sites cannot drop unsafe-inline right away, especially with a tag manager, and the auditor keeps warning about it, so this step completes by hand. A policy with unsafe-inline still limits where scripts and frames can come from, which is better than no policy.

  12. 12
    Harden sign-in

    No auditor can see these settings from outside. They decide what happens when someone guesses, buys or phishes a password.

    Do this

    • Remove default accounts and default passwords from the CMS, admin panels and databases

    • Require a second factor for every administrator, and offer it to users. Passkeys are the strongest and easiest option today

    • Rate-limit sign-in, password reset and signup, and lock or slow down after repeated failures. A CDN or WAF rule on these paths is often enough

    • Hash passwords with a slow algorithm (Argon2, bcrypt, scrypt, PBKDF2). If you use an identity provider, it does this for you

    • Expire sessions after a time that fits the data behind the login, and end them on sign-out and password change

    • Do not reveal whether an email address has an account on sign-in or reset pages

    Done when admins sign in with a second factor and sign-in is rate-limited.

  13. 13
    Lock down what sits behind the site

    A secure front door does not help if a side door is open. Databases, search engines, caches and admin ports are often reachable from the internet by accident, and leaked secrets give direct access without touching the site at all.

    Do this

    • Confirm that database, cache and search ports (5432, 3306, 6379, 9200, 27017 and others) are not reachable from outside. Test from a machine off your network, or with a port scan of your public IP

    • Make sure /.git/, /.env, /backup.zip, /phpinfo.php and similar files are not served

    • Keep secrets out of the repository and out of front-end bundles. Rotate any key that was ever committed

    • Give each service its own credentials with the least access it needs, and store them in your host's secret manager

    • Back up regularly and keep one copy where the site's own credentials cannot delete it

    • Publish /.well-known/security.txt with a Contact: address so researchers can report problems to you

    Done when a scan from outside shows only 80 and 443, and no secret lives in the code.

    Next: How to keep your website online.

Create an account, add your site as a monitored URL and work through these steps on it.

© 2026 37 Audits. All rights reserved. Audit your websites with confidence.

Supported by

Made with ❤️ in Floripa

How to secure your website | 37 Audits