Description
The JWT.php decode() has a nonstandard check to verify that "the time according to the JWT on the issuing server" is not later than "the time on the machine that is verifying the JWT", w/in some apparently statically configured leeway. This presents a problem when the server that signs the JWT has a clock that is ahead of the machine calling decode(), where the code calling decode() is punished by getting an exception thrown, saying a perfectly valid JWT is invalid. The code calling decode() is expected to configure some arbitrary $leeway variable that is likely to break again or sacrifice security.
More details:
The firebase php-jwt JWT.php has this line:
// Check that this token has been created before 'now'. This prevents
// using tokens that have been created for later use (and haven't
// correctly used the nbf claim).
if (isset($payload->iat) && $payload->iat > ($timestamp + static::$leeway)) {
throw new BeforeValidException(
'Cannot handle token prior to ' . \date(DateTime::ISO8601, $payload->iat)
);
}
According to the RFC:
The "iat" (issued at) claim identifies the time at which the JWT was
issued. This claim can be used to determine the age of the JWT. Its
value MUST be a number containing a NumericDate value. Use of this
claim is OPTIONAL.
Notice that it says nothing about validating that this timestamp is not "in the future according to the validating machine's time". Enforcing this in the JWT.php code seems like an issue, as I've already seen (it looks like the Sign In With Google server is off by about 2 seconds with my machine). It's unreasonable to assume that it's a server maintainer's fault for getting out of sync with google's server's timestamp. It seems like it would be better, if the 'iat' is in the future, to use this to offset the timestamp, instead of throwing an exception.
The current workarounds I'm pondering are if I want to set the $timestamp static variable to this offset, to sleep() until 'iat' if it isn't too far in the future, or if I want to just bite the bullet and set the $leeway and cross my fingers that I guessed a good arbitrary leeway value.
Activity