-
-
Notifications
You must be signed in to change notification settings - Fork 688
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Why validate that 'iat' is not in the future? #190
Comments
+1 |
RFC 7519 says:
In all circumstances except clock skew, it doesn't seem like it makes any sense for a JWT to be valid if, by its own claim, it hasn't been created yet. That's why we included this validation. JWT doesn't say you have to have this validation to be compliant, but it seems logical and enforces integrity in the data. I'm against removing this validation, especially when you can already easily disable it by using |
Clock skew is mentioned twice in that RFC because it's unavoidable in real-world and real-universe federated distributed systems. It's not like that's not an important circumstance. So should I fork pyjwt and make another version that is only spec-compliant and doesn't include any extrastandard assertions that seem like they make sense but aren't in the RFC? If you think the standard should enforce that check, then RFC an ammendment to the spec. Until then, it seems prudent for PyJWT to strive to implement the spec. I did an (admittedly cursory) search of the source code of jwt.io-recommended libraries for Java and JavaScript, and neither appears to perform the assertion in question
So are those two wrong? Or is no one wrong? I think it's a desirable property of the JWT community that a JWT is valid or invalid regardless of which library/language you're using. Unless either of the following are disproven that
Then we will have to agree to disagree on
Because as it stands now PyJWT is (ostensibly) rejecting valid JWTs and I want PyJWT to allow valid JWTs because when it doesn't our customers get frustrated when their valid JWTs don't work. Using What do others think? I'll fork and pull request tomorrow. |
Thanks for the PR! Just a reminder, instead of having to fork and package your own version of PyJWT, which seems a bit like overkill, you can totally bypass the check (exactly what your PR does), if you simply pass I don't like the idea of removing this check completely. Plenty of libraries have reasonable functionality that is not necessarily part of any particular spec. The strongest argument would be that we should set |
I'm with @mark-adams here. Setting |
Hi there. Since the iat check introduces a situation where the a default install of PyJWT will break in typical production circumstances (or, if you're lucky, in testing, which is what happened to me), I'd like to second the request to set verify_iat to False by default. I don't think that it's reasonable to expect any two servers to have a shared definition of "now", or to make strict checks based on time between two machines. Regardless, thank you for all the work putting this library together -- it has been really helpful and useful. :-) |
Thanks petevg! Glad you enjoy it! :-) A couple of things in response: How can it be unreasonable to assume two computers have a similar definition of when "now" is? We make these sort of assumptions all the time in all sorts of systems (public-key certificates used for HTTPS, EXP claims on JWT, TOTP-based two-factor authentication, etc.). I think it is completely reasonable, in particular when working with security, to assume two computers have a similar understanding of when "now" is. I do believe it IS unreasonable however to assume they have the EXACT same definition of now. That's why we include the ability to add the leeway parameter as almost everything on the Internet that relies on time does to compensate for the fact that exact time synchronization is hard. Setting verify_iat to default to If there's a way we can make this behavior clearer in the documentation, I'm 100% sure we'd be glad to do that. Any ideas? Thanks again for participating in the discussion 👍 |
@mark-adams: Thanks for the quick response! I think that the lightest weight change might simply to be to adjust the leeway to be something other than zero by default, and add it as an explicit param to PyJWT.decode, so that it's easy to find it with introspection tools or in the docstring for that function. As it is, I think that it's going to be pretty common for people to trip themselves up with the error if they don't know the external docs by heart. When choosing between passing a value to leeway or disabling the check, I chose to disable the check. That might be because I'm coming more from a distributed database monkey's perspective, where I use timestamps to keep a record of things and help servers do things internally, but try to use other methods for syncing state across servers. I may be missing the security implications in skipping the check. In any case, I think that I'd be happy with either solution -- just as long as the solution isn't to assume that all server clocks are perfectly in sync by default. It definitely makes sense to include it in a later version so that existing code doesn't break :-) |
I updated my PR. See explanation: #191 (comment) |
Hi, here's a real word case of this issue causing problems. Our infrastructure involves generating tokens on a server in Amazon's cloud and checking them on another one in Google's cloud using At midnight between 2016 December 31 and 2017 January 1, a leap second was introduced into UTC. Both clouds 'smeared' this second linearly over a period of time centered around that midnight: However, Amazon used 24 hour period and Google used 20 hour. This led to Amazon's clock being ahead of Google's on December 31 between 12:00:00 and 23:59:59, and our service was unavailable during most of that period due to |
So is the recommended fix to just add the Still seems annoying to be bitten by enforcing something not mentioned in the RFC. All it says is that (emph. added)
A negative age is startling I suppose, but nothing else seems to say that's forbidden. |
Sorry if it's been mentioned, I didn't catch it when I read through. First off, +1 for keeping the check, especially since it can be disabled easily. However, would it not be worthwhile to consider adding a margin to the check? Even allowing the token to be signed merely two seconds into the future, would go a long way towards solving the real-world issues this causes. If you add up issue with leap second and a small amount of slew, you could easily end with 1.2 - 1.3 seconds of difference on systems that are both relatively synced to a timesource, and two seconds would be enough to cover those cases. Also keep in mind that clocks sometimes are off by design. Some systems will jump clocks to deal with leap, others will do it "the right way", and some will gradually slew the clock. Again however, having a 2 second margin would be enough to cover it. I'm not saying 2 seconds is an ideal value, just arguing that even a tiny amount would go a long way. |
The issue is more that unless you explicitly disable the check every time or add in leeway for clock skew, this can cause random errors. The RFC talks about minutes of skew, which seems crazy, but even milliseconds of skew can cause a validation error:
Little demo:
|
nicktimko, your example would be handled just fine with leeway though? |
RFC 7519 does not specify or even suggest this type of validation on the 'iat' claim and it has caused issues for several consumers of PyJWT. This change removes the validation on future 'iat' values and leaves such things up to the application developer to implement. Fixes #190.
RFC 7519 does not specify or even suggest this type of validation on the 'iat' claim and it has caused issues for several consumers of PyJWT. This change removes the validation on future 'iat' values and leaves such things up to the application developer to implement. Fixes #190.
RFC 7519 does not specify or even suggest this type of validation on the 'iat' claim and it has caused issues for several consumers of PyJWT. This change removes the validation on future 'iat' values and leaves such things up to the application developer to implement. Fixes #190.
Remove two tests that JWT's whose `iat` value claims that they were issued in the future fail validation. These two tests fail on newer versions of PyJWT: #4672 This is because PyJWT no longer raises an exception for future `iat` times: jpadilla/pyjwt#190 PyJWT removed this validation because: - Clock skew can cause one party to generate `iat` times a few seconds or minutes ahead of another's current time - The JWT spec (RFC 7519) doesn't say that a JWT with a future `iat` should be considered invalid, these JWTs are valid - Other JWT libraries don't do this check
Remove two tests that JWT's whose `iat` value claims that they were issued in the future fail validation. These two tests fail on newer versions of PyJWT: #4672 This is because PyJWT no longer raises an exception for future `iat` times: jpadilla/pyjwt#190 PyJWT removed this validation because: - Clock skew can cause one party to generate `iat` times a few seconds or minutes ahead of another's current time - The JWT spec (RFC 7519) doesn't say that a JWT with a future `iat` should be considered invalid, these JWTs are valid - Other JWT libraries don't do this check
Update for anybody finding this discussion later:
Two other related issues:
|
In
pyjwt/jwt/api_jwt.py
Line 129 in c5ee34e
I just debugged an issue in prod where
jwt.decode()
failed because of this. Mostly because the other party's jwt lib added 'iat' a few seconds or minutes ahead of our clock time ('clock skew' as mentioned in JWT specs).I can't find any place in the specs that says that a JWT should be invalid if 'iat' is in the future. It seems like it's just there to be informative. I can use 'nbf' if I want to specify a "time before which the token MUST NOT be accepted for processing"
I consulted
So either
pass
. Regardless of whether @jpadilla wants to remove thatraise
in his lib.The text was updated successfully, but these errors were encountered: