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

Graham Leggett <> Tue, 18 July 2017 10:54 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id A53B7129459 for <>; Tue, 18 Jul 2017 03:54:03 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -2.002
X-Spam-Status: No, score=-2.002 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, HTML_MESSAGE=0.001, RP_MATCHES_RCVD=-0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (1024-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id sV84vVANRjyw for <>; Tue, 18 Jul 2017 03:54:01 -0700 (PDT)
Received: from ( []) by (Postfix) with ESMTP id 8A6D7127058 for <>; Tue, 18 Jul 2017 03:54:01 -0700 (PDT)
Received: from [] (unknown []) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) (Authenticated sender: by (Postfix) with ESMTPSA id 8B8C76B043; Tue, 18 Jul 2017 11:44:52 +0100 (BST)
DKIM-Filter: OpenDKIM Filter v2.11.0 8B8C76B043
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=default; t=1500374692; bh=yDYmlFkymIg2OAEdah7zI5yt76DdVijv4HWFc3QOCTM=; h=From:Subject:Date:In-Reply-To:Cc:To:References:From; b=cyZpTd8qxaCeELri7KdYEE6x03O6a+ekZJ5MQYDh1+oJvdtMKfZLv76zlgbJG+DK/ zphub+i/ZhXY5+xgS6I4pKn4cVOF7XzN8GpNdzWf+kEEFwIRF+IxafAYtBoN2MNOrI r2hM0QcL3FsMTB9UmNgCSU86bN2qvnajzf1DWmPk=
From: Graham Leggett <>
Message-Id: <>
Content-Type: multipart/alternative; boundary="Apple-Mail=_D323B12A-6C2B-43F9-A2EC-C660F334983A"
Mime-Version: 1.0 (Mac OS X Mail 10.3 \(3273\))
Date: Tue, 18 Jul 2017 12:53:59 +0200
In-Reply-To: <>
Cc: HTTP Working Group <>, IETF Tokbind WG <>
To: Eric Rescorla <>
References: <>
X-Mailer: Apple Mail (2.3273)
Archived-At: <>
X-Mailman-Approved-At: Tue, 18 Jul 2017 04:41:27 -0700
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: Tue, 18 Jul 2017 10:54:49 -0000

On 17 Jul 2017, at 5:18 PM, Eric Rescorla <> wrote:

> 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 —>

A few years ago I needed to solve this problem.

I needed a secure, typo-proof way of passing the original IP address from the frontend endpoints, through various reverse proxies, through various service layers which in turn were fronted with various reverse proxies, to an eventual service that cared what the IP address was.

In this scenario, it is trivial to misconfigure things and have the wrong IP address passed on, which was a problem for us.

What we had was a signed header:


The frontend endpoint would sign this header, turning X-Foo: value into the above.

Each layer that the header passed through that cared would then verify the header, and if the header verified successfully it would be passed through unchanged. If the header did not verify, the contents of the header was replaced with an error message like so and the value discarded:

X-Foo: error:signature-expired-or-whatever;

What this did was two things:

- Any value that couldn’t be verified was discarded, ie the part after the semicolon was made blank. This stopped developers ignoring the failed signatures.

- The error message was put there so that a bone could be thrown to whoever had to troubleshoot the header. The error would include the IP address of the node that discarded the value, and what the error was.

I can dig out the pattern we used, it solved a lot of practical problems with signing headers.