PHP Security and Production Hardening Hub
The starting point for securing a PHP application: route to guides on OWASP checklists, password storage, XSS/CSRF defense, production runtimes, and performance debugging.
PHP Security and Production Hardening Hub
A stack trace glittered across a public-facing staging site on a Tuesday morning. A cPanel default display_errors=on spilled database credentials into the browser of anyone who stumbled onto the wrong endpoint. That single misconfiguration, repeated across hundreds of South Florida shared hosts, is where most production incidents begin. This hub maps the checks that prevent them. It routes you by your goal: securing data, hardening the runtime, or fixing performance. Each path links to the question it answers. Follow OWASP guidance. Avoid security absolutes like 'unhackable.' Demand defensive configuration checks, not exploit recipes. In the South Florida hosting landscape, cPanel defaults and Xdebug misconfigurations are the first threat vector; everything here starts from that reality.
- Primary framework for this section: The OWASP Cheat Sheet Series, specifically the PHP Configuration Cheat Sheet and the Authentication Cheat Sheet
- Production error directive: error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT; log_errors = On; display_errors = Off
- Session cookie hardening baseline: session.cookie_secure = On, session.cookie_httponly = On, session.cookie_samesite = Lax
- Password hashing algorithm: password_hash with PASSWORD_ARGON2ID, the current PHP password storage best practice
- Default threat vector in South Florida hosting: Xdebug left enabled on production PHP-FPM pools, disabling opcache and exposing debug traces
What This Section Covers And What It Skips
This section does not rewrite the individual guides. It tells you which one to read next and why. It is built for the developer who has just inherited a codebase or a server config and needs a defensive checklist, not a textbook. Every child page answers one specific question. Use the table below to match your situation to the right deep-dive, then leave this hub behind. The OWASP Cheat Sheet Series is the backbone. Where PHP behaviour is underspecified by OWASP, the section defers to the php.net manual for the version you run. No blog-post folklore. No security-through-obscurity tricks.
What you will not find here: exploit code, zero-day hunting guides, or advice that assumes you control the kernel. The section assumes a standard shared or VPS hosting environment of the kind that runs most South Florida PHP applications. If your stack is a custom container on a dedicated orchestration layer, many of the runtime hardening pages still apply, but the server-level configuration advice stops at the PHP-FPM pool and the web-server SAPI boundary.
How To Read The Configuration Tables On The Child Pages
Every child page includes a specification table. Read the fields in this order, not the order they are printed. First, check the "What It Actually Does" column. That column translates a php.ini directive or a function call into the runtime consequence. It is where claimed security meets real behaviour. Second, check the "Failure Mode" column. A setting that is correct in isolation often fails because another extension or a framework bootstrap overrides it. The failure-mode column names the override. Third, look at the "Verify With" column. It gives you a command, a PHP script snippet, or a specific phpinfo output area that proves the setting is active. If you cannot reproduce the verification output, the configuration has not taken effect, regardless of what the INI file says. The "OWASP Reference" column is last. It is there for audit traceability, not for reading order.
Routing By Your Goal
Securing Data: Password Storage And Session Integrity
Start with the page that answers "How do I store passwords and manage sessions so that a database breach does not expose user accounts?" That page owns the PHP password storage best practice, including why argon2id is the current recommendation and when a project stuck on an older PHP minor version must fall back to bcrypt with a cost factor of at least 12. It also covers the session handler setup that prevents session fixation and cookie theft on hosts where the default file handler still writes to a world-readable /tmp.
Hardening The Runtime: php.ini And PHP-FPM
The page on PHP production runtime configuration answers the question "Which php.ini directives must change before I point a domain at this codebase, and in what order?" It walks the OWASP PHP security checklist in the sequence a cPanel MultiPHP INI editor presents the directives. That is the environment where most South Florida misconfigurations occur. The portion on PHP-FPM pool setup is separate, because a pool directive that is correct for one application can be a denial-of-service vector for another.
Fixing Performance Without Breaking Security
Opcache misconfiguration is the single largest performance drain on South Florida PHP deployments. It is almost always a side effect of leaving Xdebug enabled or setting the cache size too low for the codebase. The performance page answers "How do I configure opcache and disable Xdebug so that the first request after deploy does not trigger a CPU stampede?" It also covers the CSP header interaction: a Content-Security-Policy that is too strict breaks legitimate inline scripts, while one that is too loose negates the XSS protection you configured elsewhere.
XSS And CSRF Prevention In A Shared-Hosting Reality
The PHP XSS CSRF prevention page answers "How do I prevent cross-site scripting and cross-site request forgery when I do not control the entire server?" It gives you the output encoding rules, the CSRF token storage options that survive a file-based session handler, and the Content-Security-Policy header values that work on hosts where you cannot install mod_security rules. This page does not duplicate that content; it sends you there.
| Your Situation | Question The Page Answers | First Directive To Check |
|---|---|---|
| A public staging site shows stack traces to visitors | Which php.ini directives control error visibility in production, and what overrides them? | display_errors = Off verified at the PHP-FPM pool level |
| User sessions are stolen or reused across plain-HTTP connections | How do I configure session cookies so they are not readable by JavaScript or sent over unencrypted channels? | session.cookie_secure = On combined with session.cookie_samesite = Lax |
| A password database was breached and the hashes are being cracked | What is the current PHP password storage best practice, and how do I migrate legacy hashes? | password_hash with PASSWORD_ARGON2ID, cost factors tuned to the server hardware |
| AJAX requests hang because the session file is locked | How does the default session handler serialise writes, and what are the alternatives? | session_write_close() called before long-running AJAX handlers, or a database session handler |
| Performance drops sharply after every git push | Why is opcache clearing on deploy, and how do I warm the cache before production traffic hits? | opcache.validate_timestamps and a cache-size calculation based on script count |
OWASP PHP Security Checklist: The Section Baseline
The OWASP PHP security checklist is not a single document. It is a subset of the OWASP Cheat Sheet Series that applies to PHP deployments. This section distils it into verification steps you can run on a live server. The checklist items that matter most in a South Florida hosting context are the ones that cPanel defaults get wrong: expose_php, display_errors, session cookie flags, and the disable_functions list that many shared hosts leave empty. The child page on runtime configuration walks each item in the checklist in the order a MultiPHP INI editor presents them. If your host does not provide an INI editor and you are editing the file over SSH, the same order applies.
The checklist also covers the Content-Security-Policy header. CSP is the single most effective defence against XSS when output encoding fails. A CSP header that starts with default-src 'self' and tightens from there will break a surprising number of WordPress plugins that inject inline styles. The XSS prevention page gives you the reporting-only mode that lets you collect violation reports for a week before you enforce the policy.
PHP Production Runtime Configuration: The Order That Prevents Downtime
Change one directive at a time. Verify each with a phpinfo() page that you delete immediately after. The PHP production runtime configuration page orders the directives so that you fix the ones that leak information first, then the ones that harden the engine, then the ones that improve performance. The first directive is always display_errors. A server that shows errors to visitors is giving an attacker the file paths, the database credentials in a stack trace, and the framework version. The second is log_errors. Without it you are flying blind. The third is error_reporting, set to E_ALL & ~E_DEPRECATED & ~E_STRICT. That value logs everything that matters without filling the disk with deprecation notices from a framework on the wrong PHP version.
After the error triad, the runtime page moves to the session directives. session.cookie_secure must be On for any site that serves over HTTPS. If your South Florida host terminates TLS at a load balancer and forwards HTTP to the PHP process, the session.cookie_secure flag may need to be set conditionally based on the X-Forwarded-Proto header. The page covers that case explicitly. session.cookie_httponly blocks JavaScript access to the session cookie. That is a defence against cookie theft via XSS. session.cookie_samesite set to Lax prevents the browser from sending the session cookie on cross-site requests. It is a partial CSRF defence and a strong complement to a proper CSRF token implementation.
PHP Password Storage Best Practice: Argon2id And The Migration Path
The PHP password storage best practice page answers a single question: what algorithm and cost factors should a PHP application use right now, and how do you move a legacy user table to it without forcing a mass password reset? The answer is password_hash with PASSWORD_ARGON2ID, available in PHP 7.3 and later. Argon2id resists both side-channel attacks and GPU cracking. The memory cost, time cost, and parallelism factors are tuned to the server hardware, not copied from a blog post. The page gives you a benchmark script that measures hash time on your specific host and outputs the appropriate cost factors. On a typical cPanel shared host with a modest CPU, a memory cost tuned to the hardware and a time cost of 3 produces a hash quickly enough that a login request does not feel slow to the user.
For applications still on PHP 7.2 or earlier, the fallback is PASSWORD_BCRYPT with a cost of at least 12. The page explains the migration strategy: on login, verify the password against the legacy hash, and if it matches, re-hash it with argon2id and store the new hash. The password_needs_rehash function makes this a one-line check. This pattern avoids a mass password-reset email and lets you migrate users gradually.
PHP XSS CSRF Prevention: Defence In Layers
The PHP XSS CSRF prevention page does not give you a single magic function. It gives you the three layers that must all be present: output encoding, input validation, and a Content-Security-Policy header. Output encoding is the last line of defence. It is also the one that fails most often in PHP applications. The developer used htmlspecialchars without setting the ENT_QUOTES flag and the UTF-8 charset. Or they output user data inside a JavaScript block where HTML encoding is useless. The page specifies the exact htmlspecialchars call signature that is correct for HTML body context, HTML attribute context, and JavaScript string context. It warns that the last context is so dangerous you should avoid it entirely.
CSRF prevention on shared hosting is harder than it looks. The standard approach, a synchroniser token pattern, works only if the token is tied to the session and the session handler does not lose writes under concurrent requests. The default file-based session handler serialises requests from the same browser. An AJAX-heavy application can queue token-bearing requests and appear to hang. The CSRF page gives you the token storage alternatives: a separate cookie with the SameSite=Strict flag, a header-based token for SPAs, and a database-backed session handler for applications that cannot live with the file handler's locking behaviour. The CSP header ties the XSS and CSRF defences together. A properly configured script-src directive prevents an injected script from executing even if output encoding fails. A frame-ancestors directive prevents clickjacking, which is a CSRF variant.
More in Security and production
- How do I debug a slow PHP application? Use measurement, Xdebug profiling, MySQL slow-query analysis, and opcache inspection in that order to find and fix a slow PHP application.
- How do I prevent XSS and CSRF in PHP? Defend against XSS with output encoding and CSP headers, and prevent CSRF with session-bound tokens, following OWASP guidance for PHP applications.
- How do I secure a PHP application? A risk-prioritised security checklist for PHP applications, built on OWASP guidance and covering the lifecycle from dependency audit to production configuration.
- How does PHP run in production? How PHP-FPM workers and opcache combine to serve requests in production, and how to configure them for the South Florida hosting landscape.
- How should PHP store passwords? Use PHP's built-in password_hash with argon2id to store passwords securely, including a migration strategy from legacy hashes with password_needs_rehash.
Common Questions
What is the first php.ini directive I should change on a production server?
display_errors. Set it to Off and verify with a phpinfo() page that you delete immediately after. A server that shows errors to visitors is leaking file paths, database credentials, and framework versions.
Does the OWASP PHP security checklist cover cPanel hosting?
Yes, but you must apply it in the order the MultiPHP INI editor presents the directives. The checklist items that cPanel defaults get wrong are expose_php, display_errors, session cookie flags, and the disable_functions list.
Why does my AJAX application hang when I use the default PHP session handler?
The file-based session handler locks the session file for the duration of a request. An AJAX-heavy page sends multiple requests from the same browser session, and they queue behind the lock. Call session_write_close() early in any handler that does not need to write session data.
What is the current PHP password storage best practice?
password_hash with PASSWORD_ARGON2ID on PHP 7.3 and later. Tune the memory cost, time cost, and parallelism to your server hardware using the benchmark script on the password storage page. For older PHP versions, fall back to PASSWORD_BCRYPT with a cost of at least 12.
How do I prevent XSS when I cannot install mod_security rules on my shared host?
Use output encoding with the correct htmlspecialchars signature for each context, and deploy a Content-Security-Policy header with a tight script-src directive. Start in report-only mode, collect violation reports for a week, then enforce.
Why is Xdebug killing my production performance?
Xdebug disables or severely degrades opcache when it is loaded. A production PHP-FPM pool must have Xdebug removed or disabled in its configuration. The performance page gives you the exact check: look for the Xdebug section in phpinfo() output; if it appears, the extension is loaded.
What is the correct error_reporting value for production?
E_ALL & ~E_DEPRECATED & ~E_STRICT. This logs everything that matters without filling the disk with deprecation notices from a framework running on a PHP version it does not fully support.
Read next
- How do I prevent XSS and CSRF in PHP? Defend against XSS with output encoding and CSP headers, and prevent CSRF with session-bound tokens, following OWASP guidance for PHP applications.
- How do I secure a PHP application? A risk-prioritised security checklist for PHP applications, built on OWASP guidance and covering the lifecycle from dependency audit to production configuration.
- How should PHP store passwords? Use PHP's built-in password_hash with argon2id to store passwords securely, including a migration strategy from legacy hashes with password_needs_rehash.
- How do I debug a slow PHP application? Use measurement, Xdebug profiling, MySQL slow-query analysis, and opcache inspection in that order to find and fix a slow PHP application.
- How does PHP run in production? How PHP-FPM workers and opcache combine to serve requests in production, and how to configure them for the South Florida hosting landscape.