Skip to content

Headers with Aliasing Names

Preventing Header Spoofing Through Aliasing Header Names

Go canonicalizes header names on dashes only, therefore it handles X-Auth-User, X_Auth_User and X.Auth.User as three distinct headers.

Many backends derive their variable names from the header names (CGI, WSGI, PHP, NGINX, ...): they uppercase the header name, and replace every character that is neither a letter nor a digit with an underscore. For them, the three names above are the same HTTP_X_AUTH_USER variable.

Underscores and dots are not the only characters concerned. On top of the letters, the digits and the dash, HTTP allows the following characters in a header name:

!  #  $  %  &  '  *  +  .  ^  _  `  |  ~

Each of them is turned into an underscore by such backends, hence each of them builds an alias: X_Auth_User, X.Auth.User, X!Auth!User, X~Auth~User and X+Auth+User are all read as X-Auth-User. Only the letters, the digits and the dash are left untouched, so only the dash form is unambiguous.

As a consequence, a client can smuggle an alias of a header managed by Traefik past the middleware managing it, and have such a backend read the spoofed value instead of the value asserted by Traefik.

Configuration

The aliasHeadersStrategy entry point option is the mitigation against this class of spoofing. It controls how the request headers whose name aliases another header name are handled before routing:

  • keep (default): request headers with an aliasing name are forwarded as is.
  • delete: any request header whose name contains a character which is neither a letter, a digit, nor a dash is silently removed from the request.
  • reject: any request carrying a header whose name contains a character which is neither a letter, a digit, nor a dash is rejected with a 400 Bad Request response.

Legitimate headers are dropped too

The delete and reject strategies apply to every request header, not only to the ones Traefik manages: they cannot tell a spoofing attempt from a legitimate header whose name happens to contain such a character. An application relying on a header named for example X_Request_Id stops receiving it with delete, and its requests are rejected with reject.

In practice, header names are built with letters, digits and dashes only, and no header of the IANA registry contains any other character. A backend deliberately using such names (which a default NGINX configuration already drops for underscores) is the case to check before enabling this option.

Security Considerations

Setting aliasHeadersStrategy to delete or reject is strongly recommended when an entry point fronts a backend normalizing the header names. The middlewares managing request headers (ForwardAuth authResponseHeaders, BasicAuth and DigestAuth headerField, PassTLSClientCert, Headers customRequestHeaders, StripPrefix, ReplacePath, ...) only manage the canonical form of the headers they set, and rely on this option to not be spoofed with an aliasing name.

Traefik logs a warning at startup for every entry point left without this option configured.

entryPoints:
  websecure:
    address: ":443"
    http:
      aliasHeadersStrategy: delete  # Default: keep
[entryPoints.websecure]
  address = ":443"

  [entryPoints.websecure.http]
    aliasHeadersStrategy = "delete"
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.aliasHeadersStrategy=delete

Deprecated option

The underscoreHeadersStrategy option is deprecated in favor of aliasHeadersStrategy, which handles every aliasing character instead of the underscore only. See the feature deprecation notices for more details.