5

I have a website where virtual hosts are defined in /etc/apache2/sites-enabled/ with a header being set with the always option like this:

Header always set X-Frame-Options DENY

If I now set the same header using .htaccess in the web site's root folder, but without always then the header is returned twice in the server's response.

The setting in .htaccess (amongst others):

Header set X-Frame-Options DENY

The server's response:

HTTP/1.1 200 OK
Date: Mon, 02 May 2016 16:02:29 GMT
Server: Apache/2.4.10 (Debian)
X-Frame-Options: DENY
Cache-Control: no-cache, no-store, must-revalidate, private
Pragma: no-cache
X-XSS-Protection: 1
X-Content-Type-Options: nosniff
Last-Modified: Mon, 02 May 2016 15:03:42 GMT
Accept-Ranges: bytes
Content-Length: 0
X-Frame-Options: DENY
X-XSS-Protection: 1
X-Content-Type-Options: nosniff
Cache-Control: no-cache, no-store, must-revalidate, private
Pragma: no-cache
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

The Apache docs say that without the always option the default value of onsuccess is used. But they also say that "... the default value of onsuccess does not limit an action to responses with a 2xx status code..." (http://httpd.apache.org/docs/current/en/mod/mod_headers.html#header).

But if I don't add always, then error pages like 301s and 404s will not have the header set. On the other hand, if I do add always then the headers might be set twice if I do use the default value (i.e. onsuccess) in .htaccess. As the docs state: "repeating this directive with both conditions makes sense in some scenarios because always is not a superset of onsuccess with respect to existing headers". Setting headers twice is not always valid for an HTTP response, see https://stackoverflow.com/a/4371395/641481. So I want to avoid it, naturally.

My question now is: When exactly should I use onsuccess (i.e. the default value) and when always? I must admit that even after reading through the Apache docs a couple of times I do not exactly understand this. Pragmatically it seems that always using always leads to the correct/expected behaviour.

I also do not understand why Apache writes the header twice if it is set in always and onsuccess. It seems wrong to me, but there must be a good reason for this, since I assume the Apache-devs know a lot more than I do about HTTP ;-)

Community
  • 1
  • 1
zabbarob
  • 1,191
  • 4
  • 16
  • 25

2 Answers2

0

This is only a partial answer since it does not cover the onsuccess attribute. It is based on experiences using apache 2.4.7 running on an Ubuntu 14 os. Hope it helps you along.

The pure set parameter, without attributes, to the Header directive overwrites any always attribute by forcing the argument to Header set to be the only one delivered. If the same directive appears in a directory, i.e. file system based .htaccess file it has precedence over the same directive noted in a virtual host definition file related to that directory. If the attribute always is noted additionaly, it has the effect that any, equal or different, notation of the same directive is added to the server answer instead of overwriting/replacing it.

Probably the onsuccess attribute, which i unfortunately do not have the time to explore now, may be handled similar as the always attribute.

Michael Besteck
  • 2,415
  • 18
  • 10
  • After extensive testing, no, a ``set always`` does NOT override a ``set``. – user5994461 Jun 23 '17 at 16:03
  • @user5994461: You seem to misunderstood my words: The first sentence of the first paragraph says "Header 'set' overrides 'always'", but it does NOT say "'always' overrides 'set'". Your tests just proved my posting. Please revert the downvoting. – Michael Besteck Jun 26 '17 at 10:31
  • Not correct. Set doesn't override always and always doesn't override set. They work independently, if both are used, the http response will get 2 headers. – user5994461 Jun 26 '17 at 12:45
  • @user5994461: Jun 23 "does NOT override", Jun 26 "doesn't override always"? Have you read Q&A carefully in context? You give no details, just postulate. We should be here to search and give help an a factual base. – Michael Besteck Jun 27 '17 at 20:31
  • I tested with different combinations of settings. I linked the explanation with more details but it's already been removed by a stack overflow nazi. I am sorry, stack overflow sucks for non trivial questions and answers. – user5994461 Jun 28 '17 at 12:47
0

We use Adobe Experience Manager with a Dispatcher [caching] module for our Apache webserver. Adobe recently changed the code below. Essentially I believe you may need to use the "expr=" syntax to make sure the value is not already set. That should eliminate the duplicates.

Here's the reference code from Adobe:

Original Config: Header always append X-Frame-Options SAMEORIGIN

New Config: Header merge X-Frame-Options SAMEORIGIN "expr=%{resp:X-Frame-Options}!='SAMEORIGIN'"

When I inquired, Adobe gave me the following reasons. Thanks Adobe.

Explanation: Using "merge" instead of "append" prevents the entry's value from from being added to the header more than once.

expr=expression: The directive is applied if and only if expression evaluates to true. Details of expression syntax and evaluation are documented in the ap_expr documentation. The "expr" is looking in the response headers from the server (Publisher Application Server) to make sure that it does not include SAMEORIGIN. This ensures that SAMEORGIN is not duplicated in the response header sent back to the request client.

It's required because testing has found that when AEM included this header Apache would duplicate the SAMEORIGIN value even with the merge option. Apache is capable of proper merge when it sources the header from itself, but because the first header was set by AEM outside of the Apache instance is when it gets weird (and requires the extra expression).

It also appears that they do not use "always" with the merge+expr syntax. Perhaps to also work around an Apache weirdness.

PS... remember to change "SAMEORIGIN" for "DENY" in your case.

Dharman
  • 30,962
  • 25
  • 85
  • 135