Phase 5 · Professional ApplicationsModule 33~60 min read

Web Application Security

Threat-model a PHP application and defend its most important input, identity, authorization, browser, and dependency boundaries.

What you'll learn

Threat-model the application instead of applying isolated security snippets. You will defend input, output, identity, authorization, outbound requests, sessions, files, dependencies, and browser behavior in layers.

By the end of this lesson, you'll be able to:

  • Create a practical threat model
  • Defend XSS, CSRF, injection, SSRF, and authorization boundaries
  • Apply secure session and response policies

Core mental model

Professional PHP is less about memorizing APIs and more about choosing a clear boundary for each responsibility. Use this table as a decision guide while reading the examples.

ConceptWhat it protectsDecision rule
Trust boundaryExplicit untrusted transitionValidate whenever data crosses into a more trusted component.
AuthorizationPermitted actionCheck server-side for every resource and operation.
Defense in depthFailure containmentCombine independent controls; do not rely on one filter.

Professional workflow

Build the feature in small, verifiable steps. Each step leaves the system in a state you can test.

  1. Describe the security trust boundary boundary: its inputs, outputs, invariants, and expected failures.
  2. Implement the smallest happy path behind an explicit contract.
  3. Add validation and translate low-level failures into language the caller understands.
  4. Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
  5. Refactor only after behavior is protected by a repeatable check.

Make the boundary visible

Name inputs, outputs, side effects, and failure cases before adding framework or infrastructure code. That habit keeps advanced PHP understandable as the application grows.

Guided code lab

Issue and verify CSRF tokens

The token is unpredictable, session-bound, and compared without timing leaks.

csrf.php
<?php
function csrfToken(): string
{
    return $_SESSION['csrf'] ??= bin2hex(random_bytes(32));
}
function verifyCsrf(string $provided): void
{
    $expected = $_SESSION['csrf'] ?? '';
    if ($expected === '' || !hash_equals($expected, $provided)) {
        throw new RuntimeException('Invalid CSRF token');
    }
}

Constrain outbound URLs

A trusted base URL is configured; user input chooses only an encoded path segment, preventing arbitrary internal requests.

AvatarClient.php
<?php
final readonly class AvatarClient
{
    public function __construct(private string $trustedBaseUrl) {}
    public function fetch(string $username): string
    {
        if (!preg_match('/^[a-z0-9_-]{1,32}$/i', $username)) {
            throw new InvalidArgumentException('Invalid username');
        }
        $url = rtrim($this->trustedBaseUrl, '/') . '/' . rawurlencode($username);
        return $this->httpGet($url, timeoutSeconds: 2, maxBytes: 1_000_000);
    }
}

Production practice

Contract

Define assets, actors, entry points, abuse cases, and controls; security requirements become testable behavior.

Verification

Add negative tests for cross-user access, missing tokens, malicious markup, unsafe URLs, and oversized payloads.

Operations

Patch dependencies, rotate secrets, alert on abuse patterns, and maintain a rehearsed incident response path.

Common failure mode

Sanitizing input once does not make it safe everywhere. SQL parameters, HTML escaping, URL validation, and shell avoidance are context-specific defenses.

Independent workshop

Threat-model and harden a profile application with uploads, password changes, admin search, and avatar fetching.

Your finished workshop must include:

  • Prioritized threat model
  • Layered controls and security headers
  • Automated abuse-case suite and incident note

Definition of done

Run the happy path and at least two failure paths, explain one design tradeoff in a short README, and leave the code formatted and ready for review.

Recap & quick check

Key takeaways

  • Security starts with assets and trust boundaries.
  • Validation and encoding are context-specific.
  • Authentication is identity; authorization is permission.
  • Independent controls limit mistakes.

Quick check

1. What stops script execution in rendered user text?

2. What does CSRF exploit?

3. Where should object authorization run?

Keep the workshop: later phases deliberately build on these boundaries, so today's small example can become part of your portfolio architecture.