From 5da8744ddfb2e241cbbeedd57cb69a19a2038d3b Mon Sep 17 00:00:00 2001 From: Brad Ison Date: Thu, 8 Feb 2018 15:52:37 -0500 Subject: [PATCH] Reject JWTs with future issued-at times PyJWT stopped doing this in 1.5.0 because it's not part of the spec, and there are legitimate reasons to issue future tokens. We still want to reject these though as we don't have that need. --- util/security/jwtutil.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/util/security/jwtutil.py b/util/security/jwtutil.py index dc190838f..7e2bc6cee 100644 --- a/util/security/jwtutil.py +++ b/util/security/jwtutil.py @@ -1,5 +1,6 @@ import re +from calendar import timegm from datetime import datetime, timedelta from jwt import PyJWT from jwt.exceptions import ( @@ -42,6 +43,9 @@ class StrictJWT(PyJWT): # Do all of the other checks super(StrictJWT, self)._validate_claims(payload, options, audience, issuer, leeway, **kwargs) + now = timegm(datetime.utcnow().utctimetuple()) + self._reject_future_iat(payload, now, leeway) + if 'exp' in payload and options.get('exp_max_s') is not None: # Validate that the expiration was not more than exp_max_s seconds after the issue time # or in the absense of an issue time, more than exp_max_s in the future from now @@ -58,6 +62,16 @@ class StrictJWT(PyJWT): raise InvalidTokenError('Token was signed for more than %s seconds from %s', max_signed_s, start_time) + def _reject_future_iat(self, payload, now, leeway): + try: + iat = int(payload['iat']) + except ValueError: + raise DecodeError('Issued At claim (iat) must be an integer.') + + if iat > (now + leeway): + raise InvalidIssuedAtError('Issued At claim (iat) cannot be in' + ' the future.') + def exp_max_s_option(max_exp_s): return {