Re: [Unbearable] Dealing with header injection through reverse proxies

Willy Tarreau <> Mon, 17 July 2017 18:45 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 653CB131537 for <>; Mon, 17 Jul 2017 11:45:15 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -1.901
X-Spam-Status: No, score=-1.901 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id 85k8f_8FkITf for <>; Mon, 17 Jul 2017 11:45:13 -0700 (PDT)
Received: from ( []) by (Postfix) with ESMTP id F34EE1200ED for <>; Mon, 17 Jul 2017 11:45:12 -0700 (PDT)
Received: (from willy@localhost) by pcw.home.local (8.15.2/8.15.2/Submit) id v6HIj79i010082; Mon, 17 Jul 2017 20:45:07 +0200
Date: Mon, 17 Jul 2017 20:45:07 +0200
From: Willy Tarreau <>
To: Eric Rescorla <>
Cc: HTTP Working Group <>, IETF Tokbind WG <>
Message-ID: <>
References: <>
MIME-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: inline
In-Reply-To: <>
User-Agent: Mutt/1.6.1 (2016-04-27)
Archived-At: <>
Subject: Re: [Unbearable] Dealing with header injection through reverse proxies
X-Mailman-Version: 2.1.22
Precedence: list
List-Id: "\"This list is for discussion of proposals for doing better than bearer tokens \(e.g. HTTP cookies, OAuth tokens etc.\) for web applications. The specific goal is chartering a WG focused on preventing security token export and replay attacks.\"" <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Mon, 17 Jul 2017 18:45:15 -0000

Hi Eric,

On Mon, Jul 17, 2017 at 08:18:10AM -0700, Eric Rescorla wrote:
> i folks,
> We had a discussion today in TOKBIND about handling security-sensitive
> indications in HTTP headers (this came up in the context of
>  The
> setting here is that you have a network with a TLS reverse proxy
> serving the origin server, and the TLS proxy is responsible for doing
> some security check and telling the server about it. E.g.,
>     Client                    Proxy                     Server
>     <--- TLS w/ client auth ---> <----- HTTP with cert --->
> The client does TLS client authentication with the proxy and then
> passes the certificate to the back-end server in an injected HTTP
> header (e.g., X-Client-Certificate). In order for this to be secure,
> the proxy has to *strip* any security sensitive headers sent by the
> client. Otherwise, the client could inject their own headers that
> would appear to come from the proxy.
> Obviously, this design doesn't fail safe if the proxy fails to
> strip the headers. One way in which this can happen is if you
> have a large network of load balancers fronting a server network
> and you somehow incompletely misconfigure either the servers
> or the proxies, so that a server which supports this mechanism
> ends up behind a proxy which does not (and hence does not strip
> the headers). So, it would be nice to do something better that
> wasn't too heavyweight, especailly as a general solution.
> One natural design is simply to have a shared key between the
> proxy and the server. In that case, it's easy to demonstrate
> that the header is injected, as in [0][1]
>    X-Client-Certificate: <key>, <certificate>
> The obvious objection to this design is that it requires you to
> establish the shared key, and people were concerned about having to
> configure it into the proxy. I'm aware of a number of designs here:

What I've seen and used was slightly different :
  1) proxies unconditionally remove the header field
  2) proxies unconditionally add the new header field even with no
  3) servers verify that there is exactly one header field

This way even if step 1 above fails (eg: usual typo in the rule needed
to strip the header field which nobody notices since nobody injects
such a field name), step 2 ensures that any injection will be detected
in step 3.

In my opinion, it's important to stick to simple principles that can
be troubleshooted and fixed in field. For example I've had to deal
with signed header fields in the past and it used to be a great pain
to debug for everyone involved, to the point that people undervalue
the extra security. Simply prepending a clearly visible static value
into a field could help without adding much hassle but that's more or
less where the realistic limit lies in my opinion.