Defense in depth isn’t about adding more security tools; it’s about recognizing that any single tool can fail, and then arranging your defenses so that a failure in one layer doesn’t immediately grant an attacker full access.

Let’s see this in action with a common web application scenario. Imagine a user trying to access a sensitive API endpoint.

GET /api/v1/user/profile/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMe...

This request hits multiple security controls before it ever reaches the application logic that fetches profile data for user ID 123.

First, there’s the network layer. A Web Application Firewall (WAF) might be inspecting incoming traffic. It checks for known attack patterns, like SQL injection attempts or cross-site scripting (XSS) payloads, based on signatures. If the WAF detects something suspicious, it might block the request entirely, returning a 403 Forbidden response. This prevents malicious requests from even reaching the application servers.

# Example WAF rule (simplified)
location /api/ {
    # ... other configurations ...
    modsecurity_rules_file /etc/nginx/modsecurity/main.conf;
}

Next, the request arrives at an API Gateway. This is a crucial control point. It can handle authentication and authorization. In our example, the Authorization: Bearer ... header indicates a JWT. The API Gateway validates the JWT’s signature and checks if the token is expired. If the token is invalid or missing, the gateway rejects the request with a 401 Unauthorized or 403 Forbidden. This ensures only authenticated users can proceed.

# Example API Gateway configuration (conceptual)
routes:
  - path: "/api/v1/user/profile/{id}"
    methods: ["GET"]
    authenticate: jwt
    authorize:
      roles: ["user", "admin"]
      permissions: ["read:profile"]

If authentication and authorization pass at the gateway, the request is forwarded to the application server. Here, a second layer of authorization might exist. Even if the JWT is valid, the application logic itself must verify that the authenticated user is allowed to view the specific profile ID requested. For instance, a user should only be able to view their own profile, unless they are an administrator. This prevents privilege escalation.

# Example application logic (conceptual)
@app.route('/api/v1/user/profile/<int:user_id>', methods=['GET'])
@jwt_required()
def get_profile(user_id):
    current_user_id = get_jwt_identity()
    if user_id != current_user_id and not is_admin(current_user_id):
        return jsonify({"msg": "Forbidden"}), 403
    # ... fetch and return profile data ...

Beyond these explicit controls, other layers contribute. Network segmentation limits lateral movement. If an attacker compromises one service, they can’t easily jump to another. Encrypting data in transit (TLS/SSL) protects sensitive information from eavesdropping, even if network controls are bypassed. Data at rest encryption protects stored credentials or PII if a database is exfiltrated.

The most surprising thing about defense in depth is how much it relies on redundancy and diversity of controls, not just their presence. If your WAF, API Gateway, and application authorization all use the same underlying library for JWT validation, a vulnerability in that library compromises all three layers simultaneously. Diversity means using different technologies, vendors, or implementation strategies for each layer where possible. For example, a hardware security module (HSM) for cryptographic operations adds a layer of physical security that software-based JWT validation alone doesn’t provide.

Finally, logging and monitoring act as the ultimate fallback. Even if all other controls fail, detailed logs allow for rapid detection and response. If an unauthorized access attempt is logged, security teams can investigate, identify the bypassed controls, and remediate the vulnerability before significant damage occurs.

Once you’ve secured API access, you’ll likely want to consider how to protect the data within those API responses.

Want structured learning?

Take the full Infrastructure Security course →