Re: [OAUTH-WG] Initial JSON Web Token Best Current Practices Draft

Neil Madden <neil.madden@forgerock.com> Wed, 25 April 2018 16:57 UTC

Return-Path: <neil.madden@forgerock.com>
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 637B7128C0A for <oauth@ietfa.amsl.com>; Wed, 25 Apr 2018 09:57:15 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2.701
X-Spam-Level:
X-Spam-Status: No, score=-2.701 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=forgerock.com
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 fOmUCUj3nYCA for <oauth@ietfa.amsl.com>; Wed, 25 Apr 2018 09:57:12 -0700 (PDT)
Received: from mail-wm0-x232.google.com (mail-wm0-x232.google.com [IPv6:2a00:1450:400c:c09::232]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 607961200C5 for <oauth@ietf.org>; Wed, 25 Apr 2018 09:57:12 -0700 (PDT)
Received: by mail-wm0-x232.google.com with SMTP id j5so8059344wme.5 for <oauth@ietf.org>; Wed, 25 Apr 2018 09:57:12 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=forgerock.com; s=google; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=kEPiuWR0wNcvpbmA39pONSI4JgXaLL4X5Ti/J6DS9mk=; b=CB1Ig0622dClkAMWDXbhXcxewlPOrcY1Zqvhh67Ao4CsTnRG9vWSdfC1T35Mlww30B EeDrM6fwgep1Y5kMLTWgmtRLOqjTarLCoSUnO0ooBUdjWZUM3KDKi5FXW3Kqs5dfXWqI JFAMlVVYolr3R9sigebQi7my2ZQ+nnwyR4tm0=
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=kEPiuWR0wNcvpbmA39pONSI4JgXaLL4X5Ti/J6DS9mk=; b=JyvYbyOsXNd9BHRk+8gdW7d6ZUxWTltzFY1h9t3kQy4v7i8SQhVbPM/6PfDs0PACZn S7yGHXKafWy1qdbc0YiCSbSg5hkXhbkuZN3a3ckmlqCaNuScvd9bh19LsX9ROgQl+SxK sX6VzmuLYhy3zdlo2t4Z4FRvbs7jdCDdIh18wvxbVkVqp7PBT+LC25U2zrj2LTvqFuyG YGpmF46I9rWyy330uZXRVDwRcr8/jt2QD1ogeA1LVJ6KrCbc1SjfiC+0XWDoFSzRk/Gd piDQ3gQd9UrzDtpYjK1GPUMVA/SIKSArM/9+LUjBrHqaqhFd1Q9mRsZrCPZfvsdzb/zx 71zw==
X-Gm-Message-State: ALQs6tAy0ApktVrpg3b/Vs4Vl6NhbaYTaVGakqXtRvAPupq8R2cyQXYg m5Yjl1GXIpsAG/GwkZJ4YgmwJw==
X-Google-Smtp-Source: AB8JxZp2X/PucZYNvWvKJPOMZ9esWKo0miCvyuVHTQGYTpd4v6Av/vYPER2wWF/5qTgngzjro0iaHQ==
X-Received: by 10.28.6.14 with SMTP id 14mr15203956wmg.42.1524675430519; Wed, 25 Apr 2018 09:57:10 -0700 (PDT)
Received: from guest2s-mbp.home (72.142.200.146.dyn.plus.net. [146.200.142.72]) by smtp.gmail.com with ESMTPSA id q81sm16766381wmg.8.2018.04.25.09.57.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 25 Apr 2018 09:57:09 -0700 (PDT)
Content-Type: text/plain; charset=utf-8
Mime-Version: 1.0 (Mac OS X Mail 11.3 \(3445.6.18\))
From: Neil Madden <neil.madden@forgerock.com>
In-Reply-To: <d75a89a0-5825-b36d-e81c-efdc06bfe853@gmail.com>
Date: Wed, 25 Apr 2018 17:57:08 +0100
Cc: oauth@ietf.org
Content-Transfer-Encoding: quoted-printable
Message-Id: <792EE9B9-1955-4C4F-95D4-46AD4927B757@forgerock.com>
References: <mailman.1754.1524011314.4527.oauth@ietf.org> <d75a89a0-5825-b36d-e81c-efdc06bfe853@gmail.com>
To: Yaron Sheffer <yaronf.ietf@gmail.com>
X-Mailer: Apple Mail (2.3445.6.18)
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/1mve99bHd5GWP_tSEa01rEgUe00>
Subject: Re: [OAUTH-WG] Initial JSON Web Token Best Current Practices Draft
X-BeenThere: oauth@ietf.org
X-Mailman-Version: 2.1.22
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, 25 Apr 2018 16:57:15 -0000

Thanks Yaron,

Some responses in-line.

> On 23 Apr 2018, at 15:57, Yaron Sheffer <yaronf.ietf@gmail.com> wrote:
> 
> Hi Neil,
> 
> Thank you again for your review and the follow up. Please see my comments in-line.
> 
> 	‏Yaron
> 
>> Hi Mike,
>> I sent this originally back in June last year, I can see some of these points have been addressed in -01, but not others, so I will include further comments in-line below. (Apologies if I missed replies - I?ve realised a few messages from this WG have ended up in my spam folder).
>> As a general point, the BCP is for JWT, but some of the advice (and my points below) apply more generally to other JOSE objects (as pointed out in the introduction). Should this be reflected in the title?
>>> On 4 Jun 2017, at 15:11, Neil Madden <neil.madden@forgerock.com> wrote:
>>> 
>>> I originally set this message just to the BCP authors. As requested by Mike Jones, I am sending it here too:
>>> 
>>> Hi,
>>> 
>>> I've just seen this draft best-practice guide for JWTs pop up. I have a number of suggestions for improvements. Mostly, I think the advice is good but should be spelt out a bit more clearly. Here are some suggestions:
>>> 
>>> 1. Explicitly spell out the ECDH-ES public key validation routines from NIST. I have a blog post summarising them: https://neilmadden.wordpress.com/2017/05/17/so-how-do-you-validate-nist-ecdh-public-keys/
>> To be clear here, I think section 3.4 (Validate Cryptographic Inputs) should have text along the lines of the following added:
>> ?ECDH-ES ephemeral public key (epk) inputs should be validated according to the recipient?s chosen elliptic curve. For NIST prime-order curves P-256, P-384 and P-521, validation MUST be performed according to Section 5.6.2.3.4 ?ECC Partial Public-Key Validation Routine? of NIST Special Publication 800-56A revision 3 [1]. Where the X25519 or X448 curves of RFC 8037 [2] are used, then the implementation MAY reject any ephemeral public key that produces an all-zero ECDH shared secret as per RFC 7748 Section 6 [3]."
>> [1] https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar3.pdf
>> [2] https://tools.ietf.org/html/rfc8037
>> [3] https://tools.ietf.org/html/rfc7748#section-6
>> I should note that the final sentence about validating X25519/X448 public keys is not without some controversy. See https://moderncrypto.org/mail-archive/curves/2017/000896.html for a rabbit-hole discussion together with associated links.
>> I do not feel confident to say what the right answer is for those curves - whether to validate at all, and if so whether to blacklist bad public keys or check for an all-zero shared secret. Perhaps we should get CFRG input on this point? Or should we take RFC 7748 as being the considered CFRG opinion on this topic (and so copy the ?MAY? wording)?
> 
> I think a MAY check is useless in practice, and also, the link you mention argues quite convincingly against the 25519 check. So I propose to adopt the first part of your text.

OK, I am happy with that. My understanding is that this check should never be required for ECDH-ES as specified in JOSE.

> 
>>> 2. Recommend that (despite the -ES) ECDH is safest when *both* keys are ephemeral (eg you use some initial step to retrieve a fresh authenticated ephemeral key from the other party).
>> I think this comment is not necessary in hindsight. While fully-ephemeral ECDH has some advantages (as does static-static in some cases, e.g. NaCl crypto_box), it?s a more complicated discussion. For this BCP it is best to concentrate on ECDH-ES as specified and ensure that implementations perform proper validation of ephemeral public keys.
> 
> Agree.
> 
>>> 3. Spell out how to authenticate ECDH ephemeral keys. For instance, include an inner signed JWT that repeats the epk and possibly the apu/apv claims too.
>> This is probably a more general point that none of the public-key encryption modes in JOSE are authenticated. If sender authentication is required then nested signed-and-encrypted objects should be used.
> 
> Yes, and it's not up to the BCP to add new authenticated modes.
> 
>>> 4. Recommend that the apu and apv claims as a bare minimum include a hash of both public keys and SHOULD include any other known identifiers.
> 
> I'm not clear about "apu" in the general use case for JWT, where the identity of the recipient of a JWT is not known in advance to the sender.
> 
> Also, RFC 7518 uses "Alice" and "Bob" in these claims, and does not include any hashes. (And see my next comment).
> 
>> Section 5.8.2 of NIST SP.800-56A rev 3 (referenced in point 1 above) gives some advice on the kinds of things that should be included here. Appendix B of the same document provides some rationale for why this should be done, as does RFC 7748 Section 7 (Security Considerations). RFC 7518 (JWA) Section 4.6.2 already normatively references NIST SP.800-56A, but only for ?applications wishing to conform to [NIST.800-56A]?. In my opinion, this should be strengthened in this BCP to a SHOULD/RECOMMENDED.
>>> 5. Recommend that the receiving party recalculates the apu and apv claims from known inputs to check they match. (Or leave these out of the JWT and require the other party to recalculate them).
> 
> But this would require normative language on the contents of these claims, which does not appear in existing RFCs. I would hesitate to include such language in a BCP. There must be a very good reason for a BCP to make existing implementations non-conformant.

I don’t think the BCP has to mandate a particular format, just recommend that the recipient checks that the apu and apv claims are what it expected. One good way to do this is to recreate them from scratch.

> 
>>> 6. Provide explicit key lifetime requirements. E.g., for AES GCM this should not exceed 2^32 messages for randomly-generated IVs, and not exceed 2^64 *blocks* in total (so unless you restrict JWT lengths to less than 2^32 blocks and use a message counter as IV then this also limits to 2^32 messages). For CBC it should not exceed 2^48 messages.
>> I withdraw this comment, RFC 7518 Section 8.2 already addresses this point.
>>> 7. Require that the "alg" and "enc" claims are ONLY used to reject unexpected algorithms, NEVER to select an algorithm (even amongst a "supported" set). Cryptographic agility should be achieved by using "kid" claims that reference one of a set of known keys and the key should specify the algorithm (either explicitly or by the key parameters/size).
>> I think this is now adequately addressed by section 3.1.
>>> 8. Deprecate or strongly recommend against all of the RSA encryption modes except OAEP-256.
> 
> Yes. What about RSA with/without PSS?

I was only thinking about encryption. RSA-PSS signatures are pretty solid - although I tend to avoid them in JWT usage as the signatures themselves are quite bulky, but that’s irrelevant to the BCP.

> 
>>> 9. Strongly discourage any use of compression with encrypted JWEs - it is too easy to leak sensitive information.
>>> 10. Recommend that if a JWE is used to encrypt a password or other value for which knowing the length may be a weakness, that such fields are explicitly padded by the application or at least use CBC mode to reduce the amount of length information leaked to a multiple of the AES block size.
>> These last two points are related: encryption hides everything apart from the length of a plaintext. Compression varies the length based on the content. The combination of the two weakens the security of the encryption, but the length may already be sensitive. Applications should consider what information might be leaked in these cases and make informed decisions about whether to pad or compress content before encryption.
> 
> Agree.
> 
>>> 11. Require constant-time comparisons of HMAC tags.
>> This point is already covered by RFC 7518 Section 3.2.
>>> 12. Recommend using deterministic ECDSA signatures as described in RFC 6979 to minimise the risk of leaking the private key.
> 
> I'm not sure how this would interact with JWE. I suspect these signatures would have to be defined as a new algorithm (so out of scope for the BCP).

RFC 6979 signatures are completely compatible with (and indistinguishable from) normal ECDSA signatures. Where ECDSA requires a fresh random nonce for each signature (and fails catastrophically if you reuse a nonce even once [*]), RFC 6979 instead generates those nonces pseudorandomly as a hash over the private key and the message itself. That makes them deterministic and much more robust against accidental nonce reuse. Basically the same thing is done in EdDSA signatures (RFC 8037). The BCP can just point out that RFC 6979 exists and recommend it is used.

[*] Actually, it is even worse for ECDSA. Papers like [1] have shown that the ECDSA private key can be recovered mathematically if even just a few *bits* of the nonces are constant or guessable.
[1] https://link.springer.com/article/10.1023%2FA%3A1025436905711

> 
>>> 13. Recommend that if the ECDH calculation produces an all-zero shared secret that this is rejected.
>> This is covered in my suggestion in point 1.
>>> 14. Never produce a signed JWT containing a "sub" claim unless you are explicitly vouching for the identity of that subject. It is far too easy to accidentally produce valid OIDC id tokens from unrelated code!
>> I think this is now covered by the section on explicit typing.
>> Explicit typing is a welcome addition. A complementary approach would be to recommend using different cryptographic keys for different types of JWTs. One way to achieve this for symmetric algorithms or ECDH would be to use a key-derivation function to derive unique keys based on some domain separation string.
>> I find the discussion in section 3.2 about the ?none? algorithm unnecessary for the BCP. I would say using ?none? should not be a recommended best practice.
>> A colleague recently shared this pen-tester JWT cheat-sheet with me: https://assets.pentesterlab.com/jwt_security_cheatsheet/jwt_security_cheatsheet.pdf which hints at a few other points worth mentioning (I can draft text for these if you wish):
>> - If the ?kid? header is used to perform a lookup in a database then there is a risk of SQL/LDAP injection if the value is not validated first or appropriate interfaces used (e.g. prepared statements).
>> - The ?jwk? header should not be directly trusted, but only ever used to match a known key.
> 
> I agree about kid and jku, but I'm not familiar with all valid use cases of "jwk" so would appreciate more opinions regarding this statement.
> 
> Likewise, I?d say the ?jku? header should really be matched against a known whitelist before being trusted, as it might additionally lead to SSRF attacks if the server can be tricked into loading arbitrary URLs.
>> Kind regards,
>> Neil
>> ---
> 
> _______________________________________________
> OAuth mailing list
> OAuth@ietf.org
> https://www.ietf.org/mailman/listinfo/oauth