PCI-DSS 4.0 Req 1.3 requires that direct connections between the internet and CDE components are prohibited; Req 1.5 requires that risks from devices connecting to both untrusted networks and the CDE are addressed. Without a DMZ or filtering layer, internet traffic reaches CDE resources in one hop — a malformed webhook payload or HTTP flood hits the database network directly. CWE-668 (Exposure of Resource to Wrong Sphere) captures exactly this architecture gap. NIST SC-7 requires boundary protection at network perimeters. A WAF or reverse proxy in the DMZ also enforces rate limiting, which blocks credential-stuffing and payment enumeration attacks before they reach business logic.
Medium because the absence of a DMZ increases attack surface and removes a filtering layer that would otherwise block or rate-limit malicious traffic before it reaches CDE resources.
Place a WAF or reverse proxy (AWS WAF + ALB, Cloudflare, nginx) between the internet and your payment webhook receivers. Configure rate limiting at the DMZ layer, not in application code alone, so volumetric attacks are blocked before they consume compute resources.
resource "aws_wafv2_web_acl" "dmz" {
name = "payment-dmz-waf"
scope = "REGIONAL"
default_action { allow {} }
rule {
name = "RateLimit"
priority = 1
action { block {} }
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimit"
sampled_requests_enabled = true
}
}
}
Document the DMZ boundary in docs/cde-architecture.md with a network diagram showing traffic flows from the internet through the DMZ to the application tier.
ID: ecommerce-pci.network-security.dmz-configured
Severity: medium
What to look for: Count the number of filtering or proxy layers between internet and CDE. Look for at least 1 of: WAF (Web Application Firewall) configuration, reverse proxy (nginx, Caddy, ALB), API gateway, or dedicated DMZ security group/subnet in infrastructure code. Enumerate all internet-facing endpoints and trace the network path to CDE resources. Check for rate limiting configuration at the DMZ layer.
Pass criteria: At least 1 filtering layer exists between internet and CDE (WAF, reverse proxy, API gateway, or dedicated DMZ subnet/security group). Internet-facing traffic passes through at least 1 validation/filtering step before reaching CDE resources. At least 1 rate limiting or request filtering rule is configured at the boundary. Report: "X filtering layers found between internet and CDE."
Fail criteria: No DMZ or filtering layer evident (internet-facing services on same network as CDE with 0 intermediate filtering layers), or no WAF/proxy/gateway configured.
Skip (N/A) when: All payment processing delegated to third-party with no direct internet-to-CDE traffic (no payment webhook handlers, no payment API routes).
Detail on fail: Describe the architecture gap. Example: "Payment webhook receiver and CDE database in same security group (app-sg). 0 filtering layers between internet and CDE." or "No WAF, reverse proxy, or API gateway configured. Internet traffic reaches CDE directly."
Remediation: Implement a DMZ. Use a reverse proxy or API gateway in the DMZ layer:
# AWS WAF + ALB in DMZ
resource "aws_wafv2_web_acl" "dmz" {
name = "dmz-waf"
scope = "REGIONAL"
default_action {
allow {}
}
rule {
name = "RateLimiting"
priority = 1
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "RateLimiting"
sampled_requests_enabled = true
}
}
}
resource "aws_lb" "dmz" {
name = "dmz-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.dmz.id]
subnets = aws_subnet.dmz[*].id
}
resource "aws_lb_target_group" "webhook" {
name = "webhook-targets"
port = 443
protocol = "HTTPS"
vpc_id = aws_vpc.main.id
target_type = "ip"
health_check {
protocol = "HTTPS"
path = "/health"
}
}