Home > mod_sesehe : disguise and removal of "Server: " HTTP header in an apache module. >

Introduction

Although sending the Server header in HTTP responses is not defined as a MUST in RFC 2616, the Apache HTTP Server does not allow you to disable sending this header via it's configuration. You can reduce it to "Apache" by removing the version, or the additional modules with the ServerTokens directive. Despite what some people are saying, even mod_headers can't suppress it.
Excerpt from RFC:
"14.38 Server
The Server response-header field contains information about the software used by the origin server to handle the request. The field can contain multiple product tokens (section 3.8) and comments identifying the server and any significant subproducts. The product tokens are listed in order of their significance for identifying the application.
[ ... ]
If the response is being forwarded through a proxy, the proxy application MUST NOT modify the Server response-header. Instead, it SHOULD include a Via field (as described in section 14.45).

Note: Revealing the specific software version of the server might allow the server machine to become more vulnerable to attacks against software that is known to contain security holes. Server implementors are encouraged to make this field a configurable option.
"

In Apache httpd, the ServerTokens directive currently can at best be set to Prod, which will cause apache to return "Apache" as Server header. Some problem still occurs:
First, the level of security by obscurity of this directive is not acceptable by some people that just want to change it to some other value, without re-compiling Apache, or people that even want to simply drop the "Server: " header. Secondly, if apache is configured as a reverse proxy, and a malformed request is received, then it will display its own server token instead of the backend one, so we need to handle error response header.
I developed this tiny module by hijacking normal behavior of (reverse) proxy feature of Apache : i.e. even if a request is not a proxy request, I tag it as if it was, to make Apache core let me do what I want with this header.

Compilation and Installation

To build this module, you can proceed with a standard apxs line like this:
${APACHE_DIR}/bin/apxs -c -a -n sesehe ./mod_sesehe.c

Then, to install the compiled module, still use apxs:
${APACHE_DIR}/bin/apxs -i -a -n sesehe ./mod_sesehe.la

TODO

Next step, according to Brass, Phil (ISS Atlanta) (PBrass at iss dot net), would be to randomize header order.
An emulation of other web server (IIS/lighthttpd/etc.) by adjusting Headers order, might be a good improvement too.

Read sample_conf.conf

# The Server: header is no more displayed if this value is "on"
# Default value is "off"
SecureServerHeaderDrop "on"

# The Server: header is no more displayed when an error occurs if this value is "on"
# Default value is "off"
SecureServerHeaderErrorDrop "on"

# The Server: header that you want to display all the time.
# Default behavior is not to override Apache Server: header.
SecureServerHeader "Hidden Name"

# The Server: header that you want to display in case of error.
# Default not to override Apache Server: header.
SecureServerHeaderError "Hidden Name for errors"
 

Download mod_sesehe.c

mod_sesehe.c

Read mod_sesehe.c

  1. /* Copyright 2006 Francois Pesce : francois.pesce (at) gmail (dot) com
  2.  *
  3.  * Licensed under the Apache License, Version 2.0 (the "License");
  4.  * you may not use this file except in compliance with the License.
  5.  * You may obtain a copy of the License at
  6.  *
  7.  *     http://www.apache.org/licenses/LICENSE-2.0
  8.  *
  9.  * Unless required by applicable law or agreed to in writing, software
  10.  * distributed under the License is distributed on an "AS IS" BASIS,
  11.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12.  * See the License for the specific language governing permissions and
  13.  * limitations under the License.
  14.  */
  15.  
  16. #include <httpd.h>
  17. #include <http_config.h>
  18. #include <http_log.h>
  19. #include <http_protocol.h>
  20. #include <http_request.h>
  21. #include <util_filter.h>
  22. #include <apr_lib.h>
  23. #include <apr_strings.h>
  24.  
  25. struct sesehe_srv_conf_t
  26. {
  27.     char *server_header;
  28.     char *server_header_error;
  29.     int server_header_drop;
  30.     int server_header_error_drop;
  31. };
  32.  
  33. typedef struct sesehe_srv_conf_t sesehe_srv_conf_t;
  34.  
  35. module AP_MODULE_DECLARE_DATA sesehe_module;
  36.  
  37. static void *sesehe_create_server_config(apr_pool_t *p, server_rec *s)
  38. {
  39.     sesehe_srv_conf_t *sesehe_conf = apr_pcalloc(p, sizeof(struct sesehe_srv_conf_t));
  40.  
  41.     sesehe_conf->server_header = NULL;
  42.     sesehe_conf->server_header_error = NULL;
  43.     sesehe_conf->server_header_drop = 0;
  44.     sesehe_conf->server_header_error_drop = 0;
  45.  
  46.     return sesehe_conf;
  47. }
  48.  
  49. static const char *sesehe_set_server_header(cmd_parms *cmd, void *config, const char *arg)
  50. {
  51.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(cmd->server->module_config, &sesehe_module);
  52.  
  53.     sesehe_conf->server_header = apr_pstrdup(cmd->pool, arg);
  54.     ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, "[%s] mod_sesehe server_header is %s",
  55.                  __FUNCTION__, arg);
  56.  
  57.     return NULL;
  58. }
  59.  
  60. static const char *sesehe_set_server_header_error(cmd_parms *cmd, void *config, const char *arg)
  61. {
  62.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(cmd->server->module_config, &sesehe_module);
  63.  
  64.     sesehe_conf->server_header_error = apr_pstrdup(cmd->pool, arg);
  65.     ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, "[%s] mod_sesehe server_header_error is %s",
  66.                  __FUNCTION__, arg);
  67.  
  68.     return NULL;
  69. }
  70.  
  71. static const char *sesehe_set_server_header_drop(cmd_parms *cmd, void *config, int arg)
  72. {
  73.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(cmd->server->module_config, &sesehe_module);
  74.  
  75.     sesehe_conf->server_header_drop = arg;
  76.     ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, "[%s] mod_sesehe server_header_drop is %i",
  77.                  __FUNCTION__, arg);
  78.  
  79.     return NULL;
  80. }
  81.  
  82. static const char *sesehe_set_server_header_error_drop(cmd_parms *cmd, void *config, int arg)
  83. {
  84.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(cmd->server->module_config, &sesehe_module);
  85.  
  86.     sesehe_conf->server_header_error_drop = arg;
  87.     ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_DEBUG, 0, cmd->server, "[%s] mod_sesehe server_header_error_drop is %i",
  88.                  __FUNCTION__, arg);
  89.  
  90.     return NULL;
  91. }
  92.  
  93. static apr_status_t ap_sesehe_output_filter(ap_filter_t * f, apr_bucket_brigade * in)
  94. {
  95.     request_rec *r = f->r;
  96.     server_rec *server = r->server;
  97.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(server->module_config, &sesehe_module);
  98.  
  99.     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "sesehe_module: ap_sesehe_output_filter() %i %i",
  100.                  sesehe_conf->server_header_error_drop, sesehe_conf->server_header_drop);
  101.  
  102.     /* That will force the keep of Server: header */
  103.     if (PROXYREQ_NONE == r->proxyreq)
  104.         f->r->proxyreq = PROXYREQ_NONE - 1;
  105.  
  106.     if (0xdeadcafe == (unsigned int) f->ctx) {
  107.         if (0 == sesehe_conf->server_header_error_drop)
  108.             apr_table_setn(r->headers_out, "Server", sesehe_conf->server_header_error);
  109.         else
  110.             apr_table_unset(r->headers_out, "Server");
  111.     }
  112.     else {
  113.         if (0 == sesehe_conf->server_header_drop)
  114.             apr_table_setn(r->headers_out, "Server", sesehe_conf->server_header);
  115.         else
  116.             apr_table_unset(r->headers_out, "Server");
  117.     }
  118.  
  119.     /* remove ourselves from the filter chain */
  120.     ap_remove_output_filter(f);
  121.  
  122.     /* send the data up the stack */
  123.     return ap_pass_brigade(f->next, in);
  124. }
  125.  
  126. static void ap_sesehe_insert_output_filter(request_rec *r)
  127. {
  128.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(r->server->module_config, &sesehe_module);
  129.  
  130.     if (NULL != sesehe_conf->server_header || 1 == sesehe_conf->server_header_drop) {
  131.         ap_add_output_filter("SESEHE_OUT", NULL, r, r->connection);
  132.     }
  133. }
  134.  
  135. static void ap_sesehe_insert_error_filter(request_rec *r)
  136. {
  137.     sesehe_srv_conf_t *sesehe_conf = ap_get_module_config(r->server->module_config, &sesehe_module);
  138.  
  139.     if (NULL != sesehe_conf->server_header_error || 1 == sesehe_conf->server_header_error_drop) {
  140.         ap_add_output_filter("SESEHE_OUT", (void *) 0xdeadcafe, r, r->connection);
  141.     }
  142. }
  143.  
  144. static const command_rec sesehe_cmds[] = {
  145.     AP_INIT_TAKE1("SecureServerHeader", sesehe_set_server_header, NULL, RSRC_CONF,
  146.                   "The Server: header that you want to display all the time."),
  147.     AP_INIT_TAKE1("SecureServerHeaderError", sesehe_set_server_header_error, NULL, RSRC_CONF,
  148.                   "The Server: header that you want to display in case of error."),
  149.     AP_INIT_FLAG("SecureServerHeaderDrop", sesehe_set_server_header_drop, NULL, RSRC_CONF,
  150.                  "The Server: header is no more displayed when an error occurs if this value is \"On\"."),
  151.     AP_INIT_FLAG("SecureServerHeaderErrorDrop", sesehe_set_server_header_error_drop, NULL, RSRC_CONF,
  152.                  "The Server: header is no more displayed if this value is \"On\"."),
  153.     {NULL}
  154. };
  155.  
  156. static void sesehe_register_hooks(apr_pool_t *p)
  157. {
  158.     ap_hook_insert_filter(ap_sesehe_insert_output_filter, NULL, NULL, APR_HOOK_LAST);
  159.     ap_hook_insert_error_filter(ap_sesehe_insert_error_filter, NULL, NULL, APR_HOOK_LAST);
  160.     ap_register_output_filter("SESEHE_OUT", ap_sesehe_output_filter, NULL, AP_FTYPE_CONTENT_SET);
  161. }
  162.  
  163. module AP_MODULE_DECLARE_DATA sesehe_module = {
  164.     STANDARD20_MODULE_STUFF,
  165.     NULL,                       /* dir config creater */
  166.     NULL,                       /* dir merger */
  167.     sesehe_create_server_config,        /* server config */
  168.     NULL,                       /* merge server configs */
  169.     sesehe_cmds,                /* command apr_table_t */
  170.     sesehe_register_hooks       /* register hooks */
  171. };
  172.