Production Security And Server Hardening
Application Compromise Monitoring
The Webshell Problem
The classic post-exploitation move against PHP is dropping a .php file somewhere the web server will execute it, turning one write primitive into a persistent remote shell. Three tripwires cover it in depth. The least-privilege lesson makes writable paths non-executable, so the shell does not run. The integrity lesson's deploy manifest makes any new or changed file under the code tree an off-host alert, so the shell does not hide. And the web server's access log makes it visible in a third way: requests to PHP paths that the deploy manifest does not contain — especially POSTs to files in upload directories — are a signature worth a standing log query. A request to /uploads/cache_helper.php returning 200 is an incident, not a curiosity.
Application-Layer Signals
- Authentication anomalies: impossible travel, one account from many addresses, many accounts from one address, logins immediately followed by email or password changes. The application sees identity, so it can catch what address-based tools cannot.
- Privilege events: every grant of admin, every role change, every API key created — logged, and notified, because silent privilege escalation is how a foothold becomes ownership.
- Data-access shape: an endpoint that normally returns tens of rows suddenly paginating through millions is exfiltration's signature. Coarse per-account query volume is enough to catch it.
- Outbound calls from the app: PHP applications have a known list of services they call; a worker resolving an unfamiliar domain is either a new feature or someone else's code running in your process.
- Error-log texture: bursts of syntax errors from files that should not change,
disable_functionsviolations, include failures from odd paths — attack tooling is noisy in exactly the log developers already read.
Session and token stores deserve their own line: a stolen session bypasses authentication entirely, so notify users of new-device logins and make bulk session invalidation a one-command operation — it is the response step you will want mid-incident.
The Supply Chain Enters Here
A poisoned Composer package executes inside the application with the application's privileges — server hardening never sees it. The controls from earlier lessons converge: the committed lock file pins what runs, lock-diff review is the checkpoint where a hijacked package must pass a human, and composer audit plus dependency-alerting catch known-bad versions. Monitoring adds the behavioral layer: install-time scripts doing network I/O, and runtime egress that no dependency should explain. Vendor code is code; the integrity manifest covers vendor/ too, and a changed vendor file outside a deploy is as alarming as a changed controller.
What To Check
Before moving on, make sure you can:
- describe the webshell lifecycle and the three independent tripwires against it
- name the identity-layer anomalies only the application can see
- explain why privilege grants and session stores get first-class logging
- trace how a poisoned dependency evades server monitoring and what catches it
- write the standing log query for executed-but-not-deployed PHP paths
What You Should Be Able To Do
After this lesson, you should be able to instrument a PHP application so that webshells, account takeover, privilege escalation, exfiltration, and dependency compromise each trip an alarm, using evidence the application already produces.
Practice
Practice: Design Application Monitoring
Show solution
Identity: login events carry device fingerprints; new-device logins notify the user, impossible-travel and many-accounts-one-address patterns page the team. Password and email changes require fresh authentication and generate user-visible notifications, making account takeover loud on two channels.
Privilege: role grants, admin-panel access from new devices, and API-key creation are logged to an append-only audit table and notified in the team channel daily; grants outside business hours page.
Exfiltration: per-account and per-endpoint row-volume baselines with alerts at order-of-magnitude deviations; exports already go through a queued job, which is the natural choke point to meter.
Supply chain: lock-diff review required by branch protection, composer audit nightly, egress from app servers compared against the documented service list weekly, vendor-tree changes outside deploys page.
Response readiness is designed in: bulk session invalidation, API-key revocation, and admin lockout are each a single artisan command, rehearsed quarterly.
Practice: Diagnose A Silent Takeover
Task
Identify the missing controls in order of the attack's timeline.
Show solution
- Entry — session theft: session cookies lacking isolation from a sibling site's XSS points to cookie scoping and
HttpOnly/SameSitehygiene, but the monitoring miss is the login layer's silence: a session suddenly used from a new device and address should have notified the admin and flagged the team. Identity anomalies are the application's own signal to catch. - Persistence — weeks of validity: admin sessions with no absolute lifetime, no re-authentication for sensitive areas, and no visible active-session list gave the stolen cookie a long working life. Short admin session lifetimes and step-up auth for the admin panel bound this window structurally.
- Action — nightly exports: bulk data operations under an admin account produced no volume anomaly alert because no baseline existed, and the audit trail recorded "report generated" without row counts, filters, or destination. Audit entries for privileged operations must carry enough content to distinguish routine from theft — an export of every customer row is not the same event as a monthly summary.
- Discovery — by the victim: three months to external discovery means no detection layer worked. Any one of the three above turns this into a same-week incident.
The structural lesson: every control here is application-layer. Server hardening was never in the attack path, which is exactly why application compromise monitoring is its own discipline.
Practice: Define Application Monitoring Checks
Show solution
- Monthly planted-signal drills: a benign
.phpfixture placed in uploads must trigger the not-in-manifest alert; a test login from a fresh device must produce the user notification; a synthetic bulk read must trip the volume alarm. Each drill asserts alert delivery within its promised window. - Audit-table append-only property verified (no updates or deletes in its history), and privileged-operation coverage asserted by test: granting a role in a test environment must produce an audit row with actor, target, and before/after values.
- Session controls asserted in CI: admin session lifetime, step-up auth on the admin panel, cookie flags.
- Lock-file branch protection and nightly
composer auditfreshness monitored, with the egress-versus-documented-services diff running weekly.
Human, quarterly:
- Read one week of privilege-event notifications and confirm each grant maps to a ticket or a name — unexplained grants are the finding.
- Rehearse the response commands: bulk session invalidation and key revocation run against staging, timed, by a person who did not build them.
- Re-derive volume baselines from current traffic so growth does not turn real exfiltration into "within normal range".