CME-915

Cross-Origin Request Restriction (Reverse Proxy Origin Enforcement)

Description

Configure the reverse proxy or load balancer (nginx, Apache httpd, HAProxy) to validate the Origin and Referer headers on state-changing requests (POST, PUT, DELETE, PATCH, and WebSocket Upgrade) against an explicit allowlist of trusted origins. Requests with an Origin that does not match the allowlist are rejected with 403 before reaching the backend application. This provides defense-in-depth for applications that fail to validate cross-origin requests internally — the proxy enforces the same-origin boundary at the infrastructure layer.

CVSS Vector Impacts

Metric Transition Rationale
Attack Complexity (AC) L → H The attacker must achieve a same-origin position (e.g., XSS on the allowed domain or social engineering to access a same-origin page) to bypass the proxy-level origin restriction. A simple cross-origin request from an attacker-controlled domain is rejected by the proxy before reaching the application, significantly increasing the complexity required for successful exploitation.

CWE Relationships

Verification

Check reverse proxy configuration for Origin/Referer header validation on state-changing requests. The proxy should reject requests with an Origin not in the trusted allowlist.

$ grep -rE "valid_referers|map.*\$http_origin" /etc/nginx/
# Expected: Non-empty output — nginx origin validation map or valid_referers directive found
Platform: rhel
$ grep -rE "Require expr.*HTTP_ORIGIN|SetEnvIf Origin" /etc/httpd/conf.d/
# Expected: Non-empty output — Apache Origin validation rules found
Platform: rhel
$ grep -rE "hdr\(Origin\)|req\.hdr\(Origin\)" /etc/haproxy/
# Expected: Non-empty output — HAProxy Origin ACL rules found
Platform: rhel
$ curl -s -o /dev/null -w "%{http_code}" -X POST -H "Origin: https://evil.example.com" https://<your-app>/api/endpoint
# Expected: 403
Platform: any

Remediation

linux nginx Origin header allowlist with map-based rejection

printf 'map $http_origin $cors_allowed {
    default 0;
    "https://<trusted_origin>" 1;
    "https://<trusted_origin_2>" 1;
}

server {
    # Block state-changing cross-origin requests
    if ($request_method ~* "POST|PUT|DELETE|PATCH") {
        set $cors_check "method";
    }
    if ($cors_allowed = 0) {
        set $cors_check "${cors_check}_blocked";
    }
    if ($cors_check = "method_blocked") {
        return 403;
    }
}
' > /etc/nginx/conf.d/cme-915-origin-restrict.conf
nginx -t
nginx -s reload
linux Apache httpd Origin header enforcement via SetEnvIf and Require

printf '<IfModule mod_setenvif.c>
    SetEnvIf Origin "^https://<trusted_origin>$" ORIGIN_OK=1
    SetEnvIf Origin "^https://<trusted_origin_2>$" ORIGIN_OK=1
</IfModule>

<Location />
    <If "%%{REQUEST_METHOD} in { \x27POST\x27, \x27PUT\x27, \x27DELETE\x27, \x27PATCH\x27 }">
        <RequireAll>
            Require all granted
            Require env ORIGIN_OK
        </RequireAll>
    </If>
</Location>
' > /etc/httpd/conf.d/cme-915-origin-restrict.conf
apachectl configtest
apachectl graceful
linux HAProxy Origin header ACL with deny on mismatch

printf '\n# CME-915: Cross-Origin Request Restriction\nacl is_state_changing method POST PUT DELETE PATCH\nacl origin_present req.hdr(Origin) -m found\nacl origin_allowed req.hdr(Origin) -m str https://<trusted_origin> https://<trusted_origin_2>\nhttp-request deny deny_status 403 if is_state_changing origin_present !origin_allowed\n' >> /etc/haproxy/haproxy.cfg
haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl reload haproxy
← CME-914: Strict CORS Origin Allowlist Enforcement CME-916: SameSite Cookie Attribute Enforcement →