Re: [OAUTH-WG] client certs and TLS Terminating Reverse Proxies (was Re: I-D Action: draft-ietf-oauth-jwt-introspection-response-08.txt)

Justin Richer <jricher@mit.edu> Wed, 30 October 2019 13:24 UTC

Return-Path: <jricher@mit.edu>
X-Original-To: oauth@ietfa.amsl.com
Delivered-To: oauth@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id 2778712006F for <oauth@ietfa.amsl.com>; Wed, 30 Oct 2019 06:24:40 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -4.188
X-Spam-Level:
X-Spam-Status: No, score=-4.188 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_KAM_HTML_FONT_INVALID=0.01, URIBL_BLOCKED=0.001] autolearn=unavailable autolearn_force=no
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Yk9CBO7hyPiC for <oauth@ietfa.amsl.com>; Wed, 30 Oct 2019 06:24:38 -0700 (PDT)
Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id EF39D12081A for <oauth@ietf.org>; Wed, 30 Oct 2019 06:24:37 -0700 (PDT)
Received: from [192.168.1.7] (static-71-174-62-56.bstnma.fios.verizon.net [71.174.62.56]) (authenticated bits=0) (User authenticated as jricher@ATHENA.MIT.EDU) by outgoing.mit.edu (8.14.7/8.12.4) with ESMTP id x9UDOXFh004635 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 30 Oct 2019 09:24:34 -0400
From: Justin Richer <jricher@mit.edu>
Message-Id: <50867522-C1A5-4BE2-888A-910B352D1EC8@mit.edu>
Content-Type: multipart/alternative; boundary="Apple-Mail=_37D00C09-41F8-45E7-A039-D644BD13BB2D"
Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\))
Date: Wed, 30 Oct 2019 09:24:32 -0400
In-Reply-To: <E58B4EB0-7E59-4A0C-B43F-263CEF0B955D@forgerock.com>
Cc: Brian Campbell <bcampbell=40pingidentity.com@dmarc.ietf.org>, oauth <oauth@ietf.org>
To: Neil Madden <neil.madden@forgerock.com>
References: <2B2ACEE8-7B48-4E2D-94DA-AF3DA86DE809@mit.edu> <E58B4EB0-7E59-4A0C-B43F-263CEF0B955D@forgerock.com>
X-Mailer: Apple Mail (2.3445.104.11)
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/hfpIST8LMSq5JdSPnzZd2HdZTIA>
Subject: Re: [OAUTH-WG] client certs and TLS Terminating Reverse Proxies (was Re: I-D Action: draft-ietf-oauth-jwt-introspection-response-08.txt)
X-BeenThere: oauth@ietf.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: OAUTH WG <oauth.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/oauth>, <mailto:oauth-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/oauth/>
List-Post: <mailto:oauth@ietf.org>
List-Help: <mailto:oauth-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/oauth>, <mailto:oauth-request@ietf.org?subject=subscribe>
X-List-Received-Date: Wed, 30 Oct 2019 13:24:40 -0000

All of these problems can be solved, and I think solved better, by securing the connection between the proxy and the back-end. That way the back end will be able look not only for a specific header, but verify that the header came from the proxy itself. An obscure header name is one way to do that, but it has a lot of issues with it, especially since it’s likely to be selected once during set-up and never changed throughout the lifetime of the deployment. I think there are likely much better solutions here, and they’d address this issue without things getting weird.

And one of the best things about a standard is that you’re still free to completely ignore it if you want to, so people can and will keep following whatever proprietary patterns they want to. But at least a standard mechanism would give us a way to say to newcomers and veterans alike “No really, here’s a way that we all agree works and has these properties”. 

 — Justin

> On Oct 30, 2019, at 3:43 AM, Neil Madden <neil.madden@forgerock.com> wrote:
> 
> Replies below.
> 
>> On 29 Oct 2019, at 19:13, Justin Richer <jricher@mit.edu> wrote:
>> 
>> I would argue that making this standard would actually increase the likelihood of developers getting this right, as now instead of following some copy-pasted recipe for NGINX or Apache that they found on the web, they could turn on a standard setting that would take care of both stripping out incoming headers and injecting the appropriate values. And all of that can be covered in the security considerations with a bunch of normative text on top to make sure inbound headers are stripped. What you’re describing below is clever, but ultimately it’s just a small bit of obscurity more than anything real. 
> 
> Not really. If the header is cryptographically unguessable (eg includes a 128-bit base32-encoded string) then it provides a real security improvement. The header name becomes a bearer token effectively. There are many ways that a reverse proxy can be misconfigured in a way that compromises the security of trusted headers:
> 
> 1. There is the simple misconfiguration where you fail to strip trusted headers from incoming requests. For example in HAProxy this is the difference between set-header and add-header directives (and the add-header docs list passing a client cert to the backend as an example use case [1] despite this being insecure). Naive functional testing will still pass, but fairly basic adversarial tests would catch this. A standard header/config option might help with this simple case. 
> 
> 2. Scoping issues cause rules to not be applied where you expect them to. For example, nginx has multiple levels of scope that you can define header rules (http, server, location). But if you define *any* proxy_set_header directive at the location level (for example) it will ignore *all* such directives at the server or http levels, which can cause header-stripping rules to be silently disabled. 
> 
> 3. More advanced attacks exploit differences in how individual reverse proxies and application servers parse headers to smuggle headers or even whole requests past the RP [2]. 
> 
> Using unguessable header names for transmitting security-critical information between the RP and the app server provides an effective defense in depth against all of these attacks. (They are all forms of confused deputy attack and the unguessable header acts in the same way as an anti-CSRF token to prevent these systematically). 
> 
> (I had thought the random header name pattern was widely known, as I’ve heard it mentioned in conversations several times. But now I come to look for a definitive reference to it I can only find it mentioned in our own docs [3] and connect2id’s [4]). 
> 
> [1]: http://cbonte.github.io/haproxy-dconv/2.1/configuration.html#4.2-http-request%20add-header <http://cbonte.github.io/haproxy-dconv/2.1/configuration.html#4.2-http-request%20add-header>
> [2]: https://portswigger.net/web-security/request-smuggling <https://portswigger.net/web-security/request-smuggling>
> [3]: https://backstage.forgerock.com/docs/am/6.5/oauth2-guide/#provide-mtls-certs <https://backstage.forgerock.com/docs/am/6.5/oauth2-guide/#provide-mtls-certs>[4]: https://connect2id.com/products/server/docs/guides/tls-proxy <https://connect2id.com/products/server/docs/guides/tls-proxy> 
> 
>> 
>> The way things are today, you’ve got to not only pick a header and figure out its format, but also do the injection protection step yourself. Since all of these are disconnected, there are a lot more places that it could fall over. Even a typo where you throw out incoming “CLIENT_CERT” but inject “CLIENT_CERTS” or something like that would be disastrous. 
> 
> Most load balancers and reverse proxies support some way of setting headers that also strips the incoming header in one directive. Unless the standard gets rid of all the other ways they support to configure this (and removes all the old Stack Overflow recipes) then it won’t necessarily improve things. 
> 
> A standard that provides an explicit field for including a secret (heck, we could even call it an access token :-) that SHOULD be used might provide a significant improvement in security. 
> 
>> 
>> All in all, I am in favor of this being defined in one standard way, in addition to secure communication between proxies and backends being standardized — but this latter bit really seems like a separate problem.
> 
> I agree that that is a separate issue. 
> 
> — Neil
> 
>> 
>>  — Justin
>> 
>>> On Oct 28, 2019, at 12:32 PM, Neil Madden <neil.madden@forgerock.com <mailto:neil.madden@forgerock.com>> wrote:
>>> 
>>> While there are some benefits to standardizing headers for this kind of communication, there are some significant downsides - particularly when using headers to communicate critical security information like certs. It is *very* easy to misconfigure a reverse proxy to not strip Forwarded (or whatever) headers from incoming requests, allowing a client to simply supply a certificate as a header without authenticating the TLS connection with the corresponding private key. One good practice to prevent this is to pick a random and unguessable header name (configurable per installation) to be used for communicating the certificate, rather than using something fixed and standard. That way even if you misconfigure the proxy an attacker still has to try and guess the correct header name.
>>> 
>>> I suppose the same thing could be accomplished by having an extension for including a shared secret (or HMAC tag) in the header to authenticate it.
>>> 
>>> -- Neil
>>> 
>>>> On 28 Oct 2019, at 15:32, Brian Campbell <bcampbell=40pingidentity.com@dmarc.ietf.org <mailto:bcampbell=40pingidentity.com@dmarc.ietf.org>> wrote:
>>>> 
>>>> I don't think there's anything beyond defining something to carry the client certificate information (including the format and encoding). And it could well be a new RFC7239 parameter. Or it might just be a new HTTP header on its own.  
>>>> 
>>>> On Mon, Oct 28, 2019 at 9:05 AM Rifaat Shekh-Yusef <rifaat.ietf@gmail.com <mailto:rifaat.ietf@gmail.com>> wrote:
>>>> Thanks Brian,
>>>> 
>>>> I guess my question is: given RFC7239 and the fact that it is straightforward to secure the channel between the terminating reverse proxy and the backend service in a cluster, is there anything, from a standard perspective, that we need to do beyond defining a new parameter to carry the client certificate information?
>>>> You seem suggest that the answer is yes. If so, can you please elaborate on why is that?
>>>> 
>>>> Regards,
>>>>  Rifaat
>>>> 
>>>> 
>>>> 
>>>> On Mon, Oct 28, 2019 at 8:42 AM Brian Campbell <bcampbell@pingidentity.com <mailto:bcampbell@pingidentity.com>> wrote:
>>>> 
>>>> 
>>>> On Sat, Oct 26, 2019 at 3:55 PM Rifaat Shekh-Yusef <rifaat.ietf@gmail.com <mailto:rifaat.ietf@gmail.com>> wrote:
>>>> 
>>>> On Fri, Oct 25, 2019 at 3:47 PM Brian Campbell <bcampbell@pingidentity.com <mailto:bcampbell@pingidentity.com>> wrote:
>>>> 
>>>> I did look at RFC7239 when doing that and it could have been made to work but felt the fit wasn't quite right and would have been more cumbersome to use than not.  
>>>> 
>>>> 
>>>> Can you elaborate on this?
>>>> These days, with the zero trust model in mind, there are orchestration tools, e.g. Istio, that easily allows you to establish an MTLS channel between the reverse proxy/load balancer/API GW and the backend servers.
>>>> Why is that not sufficient? 
>>>> Which part is cumbersome?
>>>> 
>>>> What I meant was only that in the course of writing https://tools.ietf.org/html/draft-ietf-tokbind-ttrp-09 <https://tools.ietf.org/html/draft-ietf-tokbind-ttrp-09>, which aims to define HTTP header fields that enable a TLS terminating reverse proxy to convey information to a backend server about the validated Token Binding Message received from a client, it seemed more straightforward and sufficient for the use-case to use new HTTP headers to carry the information rather than to use new fields in the Forwarded header framework from RFC7239.    
>>>>  
>>>> 
>>>> CONFIDENTIALITY NOTICE: This email may contain confidential and privileged material for the sole use of the intended recipient(s). Any review, use, distribution or disclosure by others is strictly prohibited.  If you have received this communication in error, please notify the sender immediately by e-mail and delete the message and any file attachments from your computer. Thank you.
>>>> 
>>>> CONFIDENTIALITY NOTICE: This email may contain confidential and privileged material for the sole use of the intended recipient(s). Any review, use, distribution or disclosure by others is strictly prohibited..  If you have received this communication in error, please notify the sender immediately by e-mail and delete the message and any file attachments from your computer. Thank you._______________________________________________
>>>> OAuth mailing list
>>>> OAuth@ietf.org <mailto:OAuth@ietf.org>
>>>> https://www.ietf.org/mailman/listinfo/oauth <https://www.ietf.org/mailman/listinfo/oauth>
>>> _______________________________________________
>>> OAuth mailing list
>>> OAuth@ietf.org <mailto:OAuth@ietf.org>
>>> https://www.ietf.org/mailman/listinfo/oauth
>>