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

Yaron Sheffer <yaronf.ietf@gmail.com> Mon, 23 April 2018 14:57 UTC

Return-Path: <yaronf.ietf@gmail.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 F3C34129C51 for <oauth@ietfa.amsl.com>; Mon, 23 Apr 2018 07:57:36 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -2
X-Spam-Level:
X-Spam-Status: No, score=-2 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (2048-bit key) header.d=gmail.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 pbkqr_WeNMZF for <oauth@ietfa.amsl.com>; Mon, 23 Apr 2018 07:57:33 -0700 (PDT)
Received: from mail-wr0-x229.google.com (mail-wr0-x229.google.com [IPv6:2a00:1450:400c:c0c::229]) (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 7BC851270A7 for <oauth@ietf.org>; Mon, 23 Apr 2018 07:57:33 -0700 (PDT)
Received: by mail-wr0-x229.google.com with SMTP id z73-v6so42183161wrb.0 for <oauth@ietf.org>; Mon, 23 Apr 2018 07:57:33 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-language:content-transfer-encoding; bh=ArAT6oVD1M4n5kPJxhe/+ofcioup0czcPgOdCYKgmYY=; b=ozi7ZoLk8xRzopoZtICuunO3b58w/KvCNsFKV8d9xaUeMCQXCGDCqT7qbJ2XGdHGKI OWEymPZbrbD90lTRS5fm70gZj9zeTIclWuPZcvm04nIhpX/2JkBsRi3ri7ZNwWq/ZmxT EnTCdILqdZHBF4Rjr2iWTpU5IVzN6ys8appW9oKItn6AjFxpWOyHaOvH8hsqI/Z4avtQ Me4iwA97nK6QHD0CeS728vwZz8bGfmGdpX2NvoZLWdcdp9xUejD0UASQrBWw5y1qFuNh rC/H+N6Y6eGUzpfwI714M6rLH08TRhgsO5pM/aQDb7AbdmqjEY0Pf/YxnnuMFSQwEqQ5 5m5g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=ArAT6oVD1M4n5kPJxhe/+ofcioup0czcPgOdCYKgmYY=; b=QG4eX4dvo52DC/F6KXSoXosvEdau5s2XLwV2+EpoB2+w85QIL1wStEpqlyszL52p8j 3dbW7yzjMeuwHipJXqvQsr//wIUmIPYfy0QtHIwNqF4gckrbm8cS4CIvi68BAx9modTr zEztLrgzgFdqnrtF3HCKs7Ebi8nBVYUKyFsnbxMThIqZsC2lr+BzYyd3MT0RGluzXdIU wJgdhq03Zp+Q7jgYNQeBjcraMpbyCrdbTMwxz6oj6A8tCQvkN6Hw0vmVibB5PKQqY/kK CGD2wGdMt3lBEzCyqixQ9B4S1peCuUcQdZvdWxbhDELvpvIW+h0oqcOMaKPhTNxuMhmh 3ZHQ==
X-Gm-Message-State: ALQs6tAsSvLZuRgeuWJiPD5WQidopaVu7TENQeJJm7g5HJCBXwt0RqML FxXsKMCfNzsFMLmciUWHlXzHJkKn
X-Google-Smtp-Source: AB8JxZpbm/B7/6ZZzgM+3FpTOnU6bcVlAURo0pSbC6oigKWxCmev+TvbfEz/mcsYNDDfC1KliPiqcQ==
X-Received: by 2002:adf:d245:: with SMTP id o5-v6mr1061639wri.134.1524495451258; Mon, 23 Apr 2018 07:57:31 -0700 (PDT)
Received: from [172.18.129.55] (bzq-202-11.red.bezeqint.net. [212.179.202.11]) by smtp.gmail.com with ESMTPSA id m35-v6sm8196145wrm.51.2018.04.23.07.57.29 for <oauth@ietf.org> (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 23 Apr 2018 07:57:30 -0700 (PDT)
To: oauth@ietf.org
References: <mailman.1754.1524011314.4527.oauth@ietf.org>
From: Yaron Sheffer <yaronf.ietf@gmail.com>
Message-ID: <d75a89a0-5825-b36d-e81c-efdc06bfe853@gmail.com>
Date: Mon, 23 Apr 2018 17:57:28 +0300
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0
MIME-Version: 1.0
In-Reply-To: <mailman.1754.1524011314.4527.oauth@ietf.org>
Content-Type: text/plain; charset="utf-8"; format="flowed"
Content-Language: en-US
Content-Transfer-Encoding: 8bit
Archived-At: <https://mailarchive.ietf.org/arch/msg/oauth/PhHgHLnKdY9BHRHugUujL4ymRNA>
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: Mon, 23 Apr 2018 14:57:37 -0000

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.

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

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

>> 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).

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