Securing a PHP Web Application: A Practical Baseline

Ten security practices every PHP website and web application should have in place — from supported PHP versions and prepared statements to sessions, uploads and backups.

Abstract illustration of a shield over layered code panels
On this page
  1. 1. Run a supported PHP version
  2. 2. Use prepared statements for every query
  3. 3. Escape output for its context
  4. 4. Protect every state-changing form with CSRF tokens
  5. 5. Store passwords with password_hash()
  6. 6. Harden sessions and logins
  7. 7. Treat file uploads as hostile
  8. 8. Keep secrets and code out of the web root
  9. 9. Enforce HTTPS and send security headers
  10. 10. Log errors privately and back up regularly
  11. Security is a habit, not a feature

PHP powers a large share of the web, from small business websites to complex portals. Modern PHP is perfectly capable of running secure applications — but security does not happen by default. It comes from a handful of consistent habits applied everywhere in the codebase.

This article sets out a practical baseline: the measures we expect in any PHP project before it handles real users or real data.

1. Run a supported PHP version

Each PHP release receives security fixes for a limited time. Running an unsupported version means newly discovered vulnerabilities in PHP itself will never be patched. Check the official supported-versions page on php.net, plan upgrades before end of life, and keep Composer dependencies updated as well.

2. Use prepared statements for every query

SQL injection remains one of the most damaging web vulnerabilities, and it is almost entirely preventable. Use PDO or MySQLi prepared statements with bound parameters for every query that includes outside data — including values from cookies, headers and your own database. Never build SQL by concatenating user input.

3. Escape output for its context

Cross-site scripting (XSS) happens when untrusted data is placed into a page without escaping. In HTML, use htmlspecialchars() with ENT_QUOTES and UTF-8. When you must accept rich text — for example from a blog editor — run it through a maintained HTML sanitiser with a strict allowlist of tags and attributes rather than trying to strip dangerous content yourself.

4. Protect every state-changing form with CSRF tokens

Cross-site request forgery tricks a logged-in user’s browser into submitting a request they did not intend. Generate a random token per session, include it in every form that changes data, and verify it on the server with hash_equals(). Pair this with the SameSite cookie attribute for defence in depth.

5. Store passwords with password_hash()

Never store passwords in plain text or with fast hashes such as MD5 or SHA-1. PHP’s password_hash() and password_verify() handle salting and use a deliberately slow algorithm. Call password_needs_rehash() after a successful login so hashes upgrade automatically when defaults change.

6. Harden sessions and logins

  • Set session cookies as HttpOnly, Secure and SameSite, and enable strict session mode.
  • Regenerate the session ID immediately after login to prevent session fixation.
  • Expire idle sessions and limit failed login attempts per account and per IP address.
  • Show the same error message whether the email or the password was wrong.

7. Treat file uploads as hostile

Uploads are a common route to taking over a server. Limit file size, check the real content type with finfo rather than trusting the extension, generate random file names, and store files where the web server will never execute them. For images, re-encoding with GD or Imagick strips metadata and any hidden payload.

8. Keep secrets and code out of the web root

Only the files that must be publicly reachable — the front controller and static assets — belong in the public directory. Configuration files, .env files, logs, backups and the vendor folder should live above it, so a server misconfiguration cannot expose them.

9. Enforce HTTPS and send security headers

Redirect all traffic to HTTPS and enable HSTS once you are confident the whole site works securely. Add headers such as Content-Security-Policy, X-Content-Type-Options: nosniff and a sensible Referrer-Policy. A well-designed Content Security Policy can significantly limit the impact of any XSS bug that slips through.

10. Log errors privately and back up regularly

Visitors should never see stack traces, SQL errors or file paths. Turn display_errors off in production, log errors to a private location, and review the logs. Finally, automate database and file backups — and test restoring them, because a backup that has never been restored is only a hope.

Security is a habit, not a feature

None of these measures is exotic, and together they block the vast majority of attacks that target typical business websites. If you are not sure how your current PHP application measures up, a short code and configuration review is a sensible first step.

StopLord Editorial Team

Engineering & Content

Practical guides from the StopLord Technologies team on web development, mobile apps, cloud, security and digital growth.

Keep reading

Abstract illustration of a speed gauge and performance charts

Core Web Vitals Explained for Business Owners

LCP, INP and CLS in plain English: what Google’s Core Web Vitals measure, the thresholds that count as “good”, and the fixes that usually make the…

Let’s talk

Have a project in mind? Let’s build it together.

Tell us what you want to achieve. We will reply with honest advice, a clear scope and the next steps — no obligation.