How to expose a PHP app to the internet safely, using this wiki as the case study — public can read everything, only one admin can write.
The defenses
1. Authentication & sessions
- One hashed admin account (
password_hash()/password_verify()), no public signup. - Regenerate the session ID on login; gate every write behind a role check.
2. CSRF protection
Every state-changing form carries a per-session token that's verified server-side:
if (($_POST['csrf'] ?? '') !== ($_SESSION['csrf'] ?? null)) { http_response_code(400); exit; }
3. SQL — always parameterized
PDO prepared statements make SQL Injection structurally impossible:
$st = $db->prepare('SELECT * FROM pages WHERE slug = ?');
$st->execute([$slug]);
4. Output encoding
Escape everything user-influenced to stop XSS:
echo htmlspecialchars($title, ENT_QUOTES, 'UTF-8');
Checklist
| Control | Status on the wiki |
|---|---|
| Secrets outside web root | ✅ config.php above public/ |
| Parameterized queries | ✅ PDO everywhere |
| CSRF tokens on writes | ✅ |
| Output escaping | ✅ htmlspecialchars |
| Security headers | ✅ X-Frame-Options, nosniff, Referrer-Policy |
| Edge auth (optional) | Cloudflare Zero Trust and Access |
Defense in depth: app login and Cloudflare Access on
/edit*. Secrets handled per Secrets Management.