1. Output of caddy version
:
v2.6.2 h1:wKoFIxpmOJLGl3QXoo6PNbYvGW4xLEgo32GPBEjWL8o=
2. How I run Caddy:
a. System environment:
Docker, official “caddy” image
b. Command:
docker run --rm -p 127.0.0.1:81:80 -v "$(pwd)/static-service:/static-service:ro" -v "$(pwd)/Caddyfile-rewrite:/etc/caddy/Caddyfile:ro" caddy caddy version
c. Service/unit/compose file:
d. My complete Caddy config:
Variant A
Building a named matcher:
(frame-embedding-headers) {
@one-of-ours header_regexp refhost Referer "(https://(.*\.)?(domain1|domain2|domain3)\.com).*"
header not @one-of-ours X-Frame-Options "DENY"
header @one-of-ours X-Frame-Options "ALLOW-FROM {re.refhost.1}"
}
:80 {
import frame-embedding-headers
file_server /* {
root /static-service
}
}
Variant B
Spelling out the matcher in the header
directive.
(frame-embedding-headers) {
header not header_regexp refhost Referer "(https://(.*\.)?(domain1|domain2|domain3)\.com).*" X-Frame-Options "DENY"
header header_regexp refhost Referer "(https://(.*\.)?(domain1|domain2|domain3)\.com).*" X-Frame-Options "ALLOW-FROM {re.refhost.1}"
}
:80 {
import frame-embedding-headers
file_server /* {
root /static-service
}
}
Variant C
Putting the config direct, not as a snippet:
:80 {
@one-of-ours header_regexp refhost Referer "(https://(.*\.)?(domain1|domain2|domain3)\.com).*"
header not @one-of-ours X-Frame-Options "DENY"
header @one-of-ours X-Frame-Options "ALLOW-FROM {re.refhost.1}"
file_server /* {
root /static-service
}
}
3. The problem I’m having:
I want to set X-Frame-Options
to protect ancient browsers from click hijacking.
You can only set one X-Frame-Options header, with one ALLOW-FROM
domain expression.
Hence, I want to echo the Referer Header’s Host.
I tried various things that failed on a syntax level, and distilled it to two versions of valid syntax (named matcher and literal matcher), neither of which works.
4. Error messages and/or full log output:
Variant A
No Referer header:
$ curl -v http://localhost:81
* Trying 127.0.0.1:81...
* Connected to localhost (127.0.0.1) port 81 (#0)
> GET / HTTP/1.1
> Host: localhost:81
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 108
< Content-Type: text/html; charset=utf-8
< Etag: "rlecry30"
< Last-Modified: Tue, 15 Nov 2022 16:07:10 GMT
< Server: Caddy
< Date: Wed, 16 Nov 2022 14:17:26 GMT
<
<html>
<body>
</body>
</html>
* Connection #0 to host localhost left intact
Non-matching Referer header:
curl -H "Referer: https://pepi.lacht" -v http://localhost:81
* Trying 127.0.0.1:81...
* Connected to localhost (127.0.0.1) port 81 (#0)
> GET / HTTP/1.1
> Host: localhost:81
> User-Agent: curl/7.79.1
> Accept: */*
> Referer: https://pepi.lacht
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 108
< Content-Type: text/html; charset=utf-8
< Etag: "rlecry30"
< Last-Modified: Tue, 15 Nov 2022 16:07:10 GMT
< Server: Caddy
< Date: Wed, 16 Nov 2022 14:24:05 GMT
<
<html>
<body>
</body>
</html>
* Connection #0 to host localhost left intact
Expected: X-Frame-Options: DENY; Actual: No header.
Matching Referer header:
$ curl -H "Referer: https://domain1.com" -v http://localhost:81
* Trying 127.0.0.1:81...
* Connected to localhost (127.0.0.1) port 81 (#0)
> GET / HTTP/1.1
> Host: localhost:81
> User-Agent: curl/7.79.1
> Accept: */*
> Referer: https://domain1.com
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 108
< Content-Type: text/html; charset=utf-8
< Etag: "rlecry30"
< Last-Modified: Tue, 15 Nov 2022 16:07:10 GMT
< Server: Caddy
< X-Frame-Options: ALLOW-FROM https://domain1.com
< Date: Wed, 16 Nov 2022 14:25:18 GMT
<
<html>
<body>
</body>
</html>
* Connection #0 to host localhost left intact
Expected: X-Frame-Options: ALLOW-FROM https://domain1.com
Actual: X-Frame-Options: ALLOW-FROM https://domain1.com
Variant B
All three Calls give the same Output:
* Trying 127.0.0.1:81...
* Connected to localhost (127.0.0.1) port 81 (#0)
> GET / HTTP/1.1
> Host: localhost:81
> User-Agent: curl/7.79.1
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Content-Length: 108
< Content-Type: text/html; charset=utf-8
< Etag: "rlecry30"
< Last-Modified: Tue, 15 Nov 2022 16:07:10 GMT
< Server: Caddy
< X-Frame-Options: ALLOW-FROM {http.regexp.refhost.1}
< Date: Wed, 16 Nov 2022 14:32:41 GMT
<
<html>
<body>
</body>
</html>
* Connection #0 to host localhost left intact
I.e. the positive match seems to be taken no matter whether the Header is even present, but doesn’t fill the {re.…}
expression even when it should match?!
, and
Variant C
As expected behaved exactly like Variant A
5. What I already tried:
Variants A and B + a few that were rejected by validate up front.
6. Links to relevant resources:
I checked my RE with the Golang RE checker and they matched exactly as expected (incl. groups).